mirror of
https://github.com/spring-cloud/spring-cloud-netflix.git
synced 2026-09-20 00:59:01 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb7c68bfb5 | ||
|
|
953e4136f0 | ||
|
|
7d83bf71ec | ||
|
|
53199b4704 | ||
|
|
a568481baa | ||
|
|
b433afb3ba | ||
|
|
296d7020b9 | ||
|
|
acc0e3b735 | ||
|
|
80a0b53612 | ||
|
|
56fe6e616b | ||
|
|
ab6da840b6 | ||
|
|
366efb29d5 | ||
|
|
b5ecf2df16 | ||
|
|
79d3355924 | ||
|
|
d16d9ec858 | ||
|
|
146484a356 | ||
|
|
993f04a6c7 | ||
|
|
e394c1227b | ||
|
|
c1afe1d2a0 |
+46
-1
@@ -46,13 +46,58 @@ This project provides Netflix OSS integrations for Spring Boot apps through auto
|
||||
and binding to the Spring Environment and other Spring programming model idioms. With a few
|
||||
simple annotations you can quickly enable and configure the common patterns inside your
|
||||
application and build large distributed systems with battle-tested Netflix components. The
|
||||
patterns provided include Service Discovery (Eureka).
|
||||
patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix),
|
||||
Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon).
|
||||
|
||||
|
||||
== Features
|
||||
|
||||
* Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
|
||||
* Service Discovery: an embedded Eureka server can be created with declarative Java configuration
|
||||
* Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
|
||||
* Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
|
||||
* Client Side Load Balancer: Ribbon
|
||||
* External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
|
||||
* Router and Filter: automatic registration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation
|
||||
|
||||
:doctype: book
|
||||
:idprefix:
|
||||
:idseparator: -
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:tabsize: 4
|
||||
:numbered:
|
||||
:sectanchors:
|
||||
:sectnums:
|
||||
:icons: font
|
||||
:hide-uri-scheme:
|
||||
:docinfo: shared,private
|
||||
|
||||
:sc-ext: java
|
||||
:project-full-name: Spring Cloud Netflix
|
||||
|
||||
== Modules In Maintenance Mode
|
||||
|
||||
Placing a module in maintenance mode means that the Spring Cloud team will no longer be adding new features to the module.
|
||||
We will fix blocker bugs and security issues, and we will also consider and review small pull requests from the community.
|
||||
|
||||
We intend to continue to support these modules for a period of at least a year from the general availability
|
||||
of the Greenwich release train.
|
||||
|
||||
The following Spring Cloud Netflix modules and corresponding starters will be placed into maintenance mode:
|
||||
|
||||
* spring-cloud-netflix-archaius
|
||||
* spring-cloud-netflix-concurrency-limits
|
||||
* spring-cloud-netflix-hystrix-contract
|
||||
* spring-cloud-netflix-hystrix-dashboard
|
||||
* spring-cloud-netflix-hystrix-stream
|
||||
* spring-cloud-netflix-hystrix
|
||||
* spring-cloud-netflix-ribbon
|
||||
* spring-cloud-netflix-turbine-stream
|
||||
* spring-cloud-netflix-turbine
|
||||
* spring-cloud-netflix-zuul
|
||||
|
||||
NOTE: This does not include the Eureka modules.
|
||||
|
||||
|
||||
== Building
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
releaser:
|
||||
maven:
|
||||
buildCommand: ./scripts/build.sh {{systemProps}}
|
||||
+31
-6
@@ -5,21 +5,25 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-docs</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
<properties>
|
||||
<docs.main>spring-cloud-netflix</docs.main>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<configprops.inclusionPattern>
|
||||
.*.eureka.*
|
||||
.*.eureka.*|.*.hystrix.*|.*.ribbon.*|.*.sidecar.*|.*.turbine.*|.*.zuul.*|.*.archaius.*
|
||||
</configprops.inclusionPattern>
|
||||
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
@@ -28,10 +32,31 @@
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-turbine-stream</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<sourceDirectory>src/main/asciidoc</sourceDirectory>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>docs</id>
|
||||
|
||||
@@ -11,7 +11,13 @@ include::intro.adoc[]
|
||||
|
||||
* Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
|
||||
* Service Discovery: an embedded Eureka server can be created with declarative Java configuration
|
||||
* Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
|
||||
* Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
|
||||
* Client Side Load Balancer: Ribbon
|
||||
* External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
|
||||
* Router and Filter: automatic registration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation
|
||||
|
||||
include::maintenance-mode.adoc[]
|
||||
|
||||
== Building
|
||||
|
||||
|
||||
@@ -14,7 +14,14 @@
|
||||
|eureka.client.register-with-eureka | `true` | Indicates whether or not this instance should register its information with eureka server for discovery by others. In some cases, you do not want your instances to be discovered whereas you just want do discover other instances.
|
||||
|eureka.server.peer-eureka-nodes-update-interval-ms | `0` |
|
||||
|eureka.server.peer-eureka-status-refresh-time-interval-ms | `0` |
|
||||
|management.endpoint.hystrix.config | | Hystrix settings. These are traditionally set using servlet parameters. Refer to the documentation of Hystrix for more details.
|
||||
|management.endpoint.hystrix.stream.enabled | `true` | Whether to enable the hystrix.stream endpoint.
|
||||
|management.metrics.binders.hystrix.enabled | `true` | Enables creation of OK Http Client factory beans.
|
||||
|ribbon.eureka.enabled | `true` | Enables the use of Eureka with Ribbon.
|
||||
|spring.cloud.circuitbreaker.hystrix.enabled | `true` | Enables auto-configuration of the Hystrix Spring Cloud CircuitBreaker API implementation.
|
||||
|spring.cloud.loadbalancer.eureka.approximate-zone-from-hostname | `false` | Used to determine whether we should try to get the `zone` value from host name.
|
||||
|spring.cloud.loadbalancer.ribbon.enabled | `true` | Causes `RibbonLoadBalancerClient` to be used by default.
|
||||
|zuul.ribbon-isolation-strategy | |
|
||||
|zuul.ribbon.eager-load.enabled | `false` | Enables eager loading of Ribbon clients on startup.
|
||||
|
||||
|===
|
||||
@@ -1,10 +1,10 @@
|
||||
ALLOW#!/bin/bash -x
|
||||
#!/bin/bash -x
|
||||
|
||||
set -e
|
||||
|
||||
# Set default props like MAVEN_PATH, ROOT_FOLDER etc.
|
||||
function set_default_props() {
|
||||
# The script should be run from the root folder
|
||||
# The script should be executed from the root folder
|
||||
ROOT_FOLDER=`pwd`
|
||||
echo "Current folder is ${ROOT_FOLDER}"
|
||||
|
||||
@@ -65,7 +65,7 @@ function build_docs_if_applicable() {
|
||||
}
|
||||
|
||||
# Get the name of the `docs.main` property
|
||||
# Get allow branches - assumes that a `docs` module is available under `docs` profile
|
||||
# Get whitelisted branches - assumes that a `docs` module is available under `docs` profile
|
||||
function retrieve_doc_properties() {
|
||||
MAIN_ADOC_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
@@ -75,14 +75,14 @@ function retrieve_doc_properties() {
|
||||
echo "Extracted 'main.adoc' from Maven build [${MAIN_ADOC_VALUE}]"
|
||||
|
||||
|
||||
ALLOW_PROPERTY=${ALLOW_PROPERTY:-"docs.allowed.branches"}
|
||||
ALLOWED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
WHITELIST_PROPERTY=${WHITELIST_PROPERTY:-"docs.whitelisted.branches"}
|
||||
WHITELISTED_BRANCHES_VALUE=$("${MAVEN_PATH}"mvn -q \
|
||||
-Dexec.executable="echo" \
|
||||
-Dexec.args="\${${ALLOW_PROPERTY}}" \
|
||||
-Dexec.args="\${${WHITELIST_PROPERTY}}" \
|
||||
org.codehaus.mojo:exec-maven-plugin:1.3.1:exec \
|
||||
-P docs \
|
||||
-pl docs)
|
||||
echo "Extracted '${ALLOW_PROPERTY}' from Maven build [${ALLOWED_BRANCHES_VALUE}]"
|
||||
echo "Extracted '${WHITELIST_PROPERTY}' from Maven build [${WHITELISTED_BRANCHES_VALUE}]"
|
||||
}
|
||||
|
||||
# Stash any outstanding changes
|
||||
@@ -148,9 +148,9 @@ function copy_docs_for_current_version() {
|
||||
else
|
||||
echo -e "Current branch is [${CURRENT_BRANCH}]"
|
||||
# https://stackoverflow.com/questions/29300806/a-bash-script-to-check-if-a-string-is-present-in-a-comma-separated-list-of-strin
|
||||
if [[ ",${ALLOWED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then
|
||||
if [[ ",${WHITELISTED_BRANCHES_VALUE}," = *",${CURRENT_BRANCH},"* ]] ; then
|
||||
mkdir -p ${ROOT_FOLDER}/${CURRENT_BRANCH}
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is allowed! Will copy the current docs to the [${CURRENT_BRANCH}] folder"
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is whitelisted! Will copy the current docs to the [${CURRENT_BRANCH}] folder"
|
||||
for f in docs/target/generated-docs/*; do
|
||||
file=${f#docs/target/generated-docs/*}
|
||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||
@@ -169,7 +169,7 @@ function copy_docs_for_current_version() {
|
||||
done
|
||||
COMMIT_CHANGES="yes"
|
||||
else
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is not on the allow list! Check out the Maven [${ALLOW_PROPERTY}] property in
|
||||
echo -e "Branch [${CURRENT_BRANCH}] is not on the white list! Check out the Maven [${WHITELIST_PROPERTY}] property in
|
||||
[docs] module available under [docs] profile. Won't commit any changes to gh-pages for this branch."
|
||||
fi
|
||||
fi
|
||||
@@ -250,10 +250,10 @@ the script will work in the following manner:
|
||||
|
||||
- if there's no gh-pages / target for docs module then the script ends
|
||||
- for main branch the generated docs are copied to the root of gh-pages branch
|
||||
- for any other branch (if that branch is allowed) a subfolder with branch name is created
|
||||
- for any other branch (if that branch is whitelisted) a subfolder with branch name is created
|
||||
and docs are copied there
|
||||
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
|
||||
with that version number will be created in the gh-pages branch. WARNING! No allow verification will take place
|
||||
with that version number will be created in the gh-pages branch. WARNING! No whitelist verification will take place
|
||||
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
|
||||
switch to gh-pages of that repo and copy the generated docs to `docs/<project-name>/<version>`
|
||||
- if the destination switch is passed (-d) then the script will check if the provided dir is a git repo and then will
|
||||
@@ -327,4 +327,4 @@ build_docs_if_applicable
|
||||
retrieve_doc_properties
|
||||
stash_changes
|
||||
add_docs_from_target
|
||||
checkout_previous_branch
|
||||
checkout_previous_branch
|
||||
@@ -4,5 +4,6 @@ This project provides Netflix OSS integrations for Spring Boot apps through auto
|
||||
and binding to the Spring Environment and other Spring programming model idioms. With a few
|
||||
simple annotations you can quickly enable and configure the common patterns inside your
|
||||
application and build large distributed systems with battle-tested Netflix components. The
|
||||
patterns provided include Service Discovery (Eureka).
|
||||
patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix),
|
||||
Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon).
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
include::_attributes.adoc[]
|
||||
|
||||
== Modules In Maintenance Mode
|
||||
|
||||
Placing a module in maintenance mode means that the Spring Cloud team will no longer be adding new features to the module.
|
||||
We will fix blocker bugs and security issues, and we will also consider and review small pull requests from the community.
|
||||
|
||||
We intend to continue to support these modules for a period of at least a year from the general availability
|
||||
of the Greenwich release train.
|
||||
|
||||
The following Spring Cloud Netflix modules and corresponding starters will be placed into maintenance mode:
|
||||
|
||||
* spring-cloud-netflix-archaius
|
||||
* spring-cloud-netflix-concurrency-limits
|
||||
* spring-cloud-netflix-hystrix-contract
|
||||
* spring-cloud-netflix-hystrix-dashboard
|
||||
* spring-cloud-netflix-hystrix-stream
|
||||
* spring-cloud-netflix-hystrix
|
||||
* spring-cloud-netflix-ribbon
|
||||
* spring-cloud-netflix-turbine-stream
|
||||
* spring-cloud-netflix-turbine
|
||||
* spring-cloud-netflix-zuul
|
||||
|
||||
NOTE: This does not include the Eureka modules.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Cloud Netflix provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka).
|
||||
Spring Cloud Netflix provides Netflix OSS integrations for Spring Boot apps through autoconfiguration and binding to the Spring Environment and other Spring programming model idioms. With a few simple annotations you can quickly enable and configure the common patterns inside your application and build large distributed systems with battle-tested Netflix components. The patterns provided include Service Discovery (Eureka), Circuit Breaker (Hystrix), Intelligent Routing (Zuul) and Client Side Load Balancing (Ribbon)..
|
||||
|
||||
## Features
|
||||
|
||||
@@ -6,16 +6,23 @@ Spring Cloud Netflix features:
|
||||
|
||||
* Service Discovery: Eureka instances can be registered and clients can discover the instances using Spring-managed beans
|
||||
* Service Discovery: an embedded Eureka server can be created with declarative Java configuration
|
||||
* Circuit Breaker: Hystrix clients can be built with a simple annotation-driven method decorator
|
||||
* Circuit Breaker: embedded Hystrix dashboard with declarative Java configuration
|
||||
* Declarative REST Client: Feign creates a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotations
|
||||
* Client Side Load Balancer: Ribbon
|
||||
* External Configuration: a bridge from the Spring Environment to Archaius (enables native configuration of Netflix components using Spring Boot conventions)
|
||||
* Router and Filter: automatic registration of Zuul filters, and a simple convention over configuration approach to reverse proxy creation
|
||||
|
||||
## Getting Started
|
||||
|
||||
As long as Spring Cloud Netflix and Eureka Core are on the
|
||||
classpath any Spring Boot application with `spring-cloud-starter-netflix-eureka-client` in dependencies will try to contact a Eureka
|
||||
classpath any Spring Boot application with `@EnableEurekaClient` will try to contact a Eureka
|
||||
server on `http://localhost:8761` (the default value of
|
||||
`eureka.client.serviceUrl.defaultZone`):
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@RestController
|
||||
public class Application {
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
include::_attributes.adoc[]
|
||||
=== Disabling Spring Cloud Circuit Breaker Hystrix
|
||||
|
||||
You can disable the auto-configuration by setting `spring.cloud.circuitbreaker.hystrix.enabled`
|
||||
to `false`.
|
||||
|
||||
=== Configuring Hystrix Circuit Breakers
|
||||
|
||||
==== Default Configuration
|
||||
|
||||
To provide a default configuration for all of your circuit breakers create a `Customize` bean that is passed a
|
||||
`HystrixCircuitBreakerFactory` or `ReactiveHystrixCircuitBreakerFactory`.
|
||||
The `configureDefault` method can be used to provide a default configuration.
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Customizer<HystrixCircuitBreakerFactory> defaultConfig() {
|
||||
return factory -> factory.configureDefault(id -> HystrixCommand.Setter
|
||||
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(id))
|
||||
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
.withExecutionTimeoutInMilliseconds(4000)));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
===== Reactive Example
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Customizer<ReactiveHystrixCircuitBreakerFactory> defaultConfig() {
|
||||
return factory -> factory.configureDefault(id -> HystrixObservableCommand.Setter
|
||||
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(id))
|
||||
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
|
||||
.withExecutionTimeoutInMilliseconds(4000)));
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
==== Specific Circuit Breaker Configuration
|
||||
|
||||
Similarly to providing a default configuration, you can create a `Customize` bean this is passed a
|
||||
`HystrixCircuitBreakerFactory`
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Customizer<HystrixCircuitBreakerFactory> customizer() {
|
||||
return factory -> factory.configure(builder -> builder.commandProperties(
|
||||
HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(2000)), "foo", "bar");
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
===== Reactive Example
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
@Bean
|
||||
public Customizer<ReactiveHystrixCircuitBreakerFactory> customizer() {
|
||||
return factory -> factory.configure(builder -> builder.commandProperties(
|
||||
HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(2000)), "foo", "bar");
|
||||
}
|
||||
----
|
||||
====
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,14 +3,14 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Netflix</name>
|
||||
<description>Spring Cloud Netflix</description>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.3.6.BUILD-SNAPSHOT</version>
|
||||
<relativePath />
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -21,8 +21,11 @@
|
||||
</scm>
|
||||
<properties>
|
||||
<bintray.package>netflix</bintray.package>
|
||||
<spring-cloud-commons.version>3.1.0-M3</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>3.1.0-M3</spring-cloud-config.version>
|
||||
<spring-cloud-commons.version>2.2.10.BUILD-SNAPSHOT</spring-cloud-commons.version>
|
||||
<spring-cloud-config.version>2.2.8.RELEASE</spring-cloud-config.version>
|
||||
<spring-cloud-stream.version>Horsham.SR13</spring-cloud-stream.version>
|
||||
<!-- Has to be a stable version (not one that depends on this version of netflix): -->
|
||||
<donotreplacespring-cloud-contract.version>2.2.4.RELEASE</donotreplacespring-cloud-contract.version>
|
||||
|
||||
<!-- Sonar -->
|
||||
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
|
||||
@@ -30,7 +33,6 @@
|
||||
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
|
||||
<sonar.language>java</sonar.language>
|
||||
<eureka-jersey.version>1.19.4</eureka-jersey.version>
|
||||
<maven-resources-plugin.version>3.1.0</maven-resources-plugin.version>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
@@ -76,6 +78,12 @@
|
||||
</build>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix-contract</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
@@ -103,11 +111,38 @@
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-stream-dependencies</artifactId>
|
||||
<version>${spring-cloud-stream.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-contract-dependencies</artifactId>
|
||||
<version>${donotreplacespring-cloud-contract.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
<artifactId>javax.inject</artifactId>
|
||||
<version>1</version>
|
||||
</dependency>
|
||||
<!-- archaius dependencies that are now runtime -->
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<version>1.8</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- end archaius deps -->
|
||||
<!-- Eureka core dep that is now optional -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
@@ -147,10 +182,22 @@
|
||||
</reporting>
|
||||
<modules>
|
||||
<module>spring-cloud-netflix-dependencies</module>
|
||||
<module>spring-cloud-netflix-archaius</module>
|
||||
<!-- Not part of the reactor build: build and deploy separately -->
|
||||
<!--module>spring-cloud-netflix-hystrix-contract</module-->
|
||||
<module>spring-cloud-netflix-core</module>
|
||||
<module>spring-cloud-netflix-concurrency-limits</module>
|
||||
<module>spring-cloud-netflix-hystrix-dashboard</module>
|
||||
<module>spring-cloud-netflix-hystrix-stream</module>
|
||||
<module>spring-cloud-netflix-eureka-client</module>
|
||||
<module>spring-cloud-netflix-eureka-server</module>
|
||||
<module>spring-cloud-starter-netflix-eureka-client</module>
|
||||
<module>spring-cloud-starter-netflix-eureka-server</module>
|
||||
<module>spring-cloud-netflix-turbine</module>
|
||||
<module>spring-cloud-netflix-turbine-stream</module>
|
||||
<module>spring-cloud-netflix-sidecar</module>
|
||||
<module>spring-cloud-netflix-zuul</module>
|
||||
<module>spring-cloud-netflix-ribbon</module>
|
||||
<module>spring-cloud-starter-netflix</module>
|
||||
<module>spring-cloud-netflix-hystrix</module>
|
||||
<module>spring-cloud-netflix-eureka-client-tls-tests</module>
|
||||
<module>docs</module>
|
||||
</modules>
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -o errexit
|
||||
|
||||
(cd spring-cloud-netflix-hystrix-contract && ../mvnw clean install -B -Pdocs ${@})
|
||||
./mvnw clean install -B -Pdocs ${@}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
|
||||
|
||||
<artifactId>spring-cloud-netflix-archaius</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Netflix Archaius</name>
|
||||
<description>Spring Cloud Netflix Archaius</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-configuration</groupId>
|
||||
<artifactId>commons-configuration</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
+241
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
import com.netflix.config.AggregatedConfiguration;
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DeploymentContext;
|
||||
import com.netflix.config.DynamicProperty;
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicURLConfiguration;
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.apache.commons.configuration.ConfigurationBuilder;
|
||||
import org.apache.commons.configuration.EnvironmentConfiguration;
|
||||
import org.apache.commons.configuration.SystemConfiguration;
|
||||
import org.apache.commons.configuration.event.ConfigurationEvent;
|
||||
import org.apache.commons.configuration.event.ConfigurationListener;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.autoconfigure.endpoint.condition.ConditionalOnAvailableEndpoint;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureOrder;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static com.netflix.config.ConfigurationManager.APPLICATION_PROPERTIES;
|
||||
import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_ENV_CONFIG;
|
||||
import static com.netflix.config.ConfigurationManager.DISABLE_DEFAULT_SYS_CONFIG;
|
||||
import static com.netflix.config.ConfigurationManager.ENV_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.SYS_CONFIG_NAME;
|
||||
import static com.netflix.config.ConfigurationManager.URL_CONFIG_NAME;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @author Liang Yong
|
||||
*/
|
||||
@Lazy(false)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass({ ConcurrentCompositeConfiguration.class,
|
||||
ConfigurationBuilder.class })
|
||||
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class ArchaiusAutoConfiguration {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ArchaiusAutoConfiguration.class);
|
||||
|
||||
private static final AtomicBoolean initialized = new AtomicBoolean(false);
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment env;
|
||||
|
||||
@Autowired(required = false)
|
||||
private List<AbstractConfiguration> externalConfigurations = new ArrayList<>();
|
||||
|
||||
private static DynamicURLConfiguration defaultURLConfig;
|
||||
|
||||
@PreDestroy
|
||||
public void close() {
|
||||
if (defaultURLConfig != null) {
|
||||
defaultURLConfig.stopLoading();
|
||||
}
|
||||
setStatic(ConfigurationManager.class, "instance", null);
|
||||
setStatic(ConfigurationManager.class, "customConfigurationInstalled", false);
|
||||
setStatic(DynamicPropertyFactory.class, "config", null);
|
||||
setStatic(DynamicPropertyFactory.class, "initializedWithDefaultConfig", false);
|
||||
setStatic(DynamicProperty.class, "dynamicPropertySupportImpl", null);
|
||||
initialized.compareAndSet(true, false);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static ConfigurableEnvironmentConfiguration configurableEnvironmentConfiguration(
|
||||
ConfigurableEnvironment env, ApplicationContext context) {
|
||||
Map<String, AbstractConfiguration> abstractConfigurationMap = context
|
||||
.getBeansOfType(AbstractConfiguration.class);
|
||||
List<AbstractConfiguration> externalConfigurations = new ArrayList<>(
|
||||
abstractConfigurationMap.values());
|
||||
ConfigurableEnvironmentConfiguration envConfig = new ConfigurableEnvironmentConfiguration(
|
||||
env);
|
||||
configureArchaius(envConfig, env, externalConfigurations);
|
||||
return envConfig;
|
||||
}
|
||||
|
||||
protected static void configureArchaius(
|
||||
ConfigurableEnvironmentConfiguration envConfig, ConfigurableEnvironment env,
|
||||
List<AbstractConfiguration> externalConfigurations) {
|
||||
if (initialized.compareAndSet(false, true)) {
|
||||
String appName = env.getProperty("spring.application.name");
|
||||
if (appName == null) {
|
||||
appName = "application";
|
||||
log.warn("No spring.application.name found, defaulting to 'application'");
|
||||
}
|
||||
System.setProperty(DeploymentContext.ContextKey.appId.getKey(), appName);
|
||||
|
||||
ConcurrentCompositeConfiguration config = new ConcurrentCompositeConfiguration();
|
||||
|
||||
// support to add other Configurations (Jdbc, DynamoDb, Zookeeper, jclouds,
|
||||
// etc...)
|
||||
if (externalConfigurations != null) {
|
||||
for (AbstractConfiguration externalConfig : externalConfigurations) {
|
||||
config.addConfiguration(externalConfig);
|
||||
}
|
||||
}
|
||||
config.addConfiguration(envConfig,
|
||||
ConfigurableEnvironmentConfiguration.class.getSimpleName());
|
||||
|
||||
defaultURLConfig = new DynamicURLConfiguration();
|
||||
try {
|
||||
config.addConfiguration(defaultURLConfig, URL_CONFIG_NAME);
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
log.error("Cannot create config from " + defaultURLConfig, ex);
|
||||
}
|
||||
|
||||
// TODO: sys/env above urls?
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_SYS_CONFIG)) {
|
||||
SystemConfiguration sysConfig = new SystemConfiguration();
|
||||
config.addConfiguration(sysConfig, SYS_CONFIG_NAME);
|
||||
}
|
||||
if (!Boolean.getBoolean(DISABLE_DEFAULT_ENV_CONFIG)) {
|
||||
EnvironmentConfiguration environmentConfiguration = new EnvironmentConfiguration();
|
||||
config.addConfiguration(environmentConfiguration, ENV_CONFIG_NAME);
|
||||
}
|
||||
|
||||
ConcurrentCompositeConfiguration appOverrideConfig = new ConcurrentCompositeConfiguration();
|
||||
config.addConfiguration(appOverrideConfig, APPLICATION_PROPERTIES);
|
||||
config.setContainerConfigurationIndex(
|
||||
config.getIndexOfConfiguration(appOverrideConfig));
|
||||
|
||||
addArchaiusConfiguration(config);
|
||||
}
|
||||
else {
|
||||
// TODO: reinstall ConfigurationManager
|
||||
log.warn(
|
||||
"Netflix ConfigurationManager has already been installed, unable to re-install");
|
||||
}
|
||||
}
|
||||
|
||||
private static void addArchaiusConfiguration(
|
||||
ConcurrentCompositeConfiguration config) {
|
||||
if (ConfigurationManager.isConfigurationInstalled()) {
|
||||
AbstractConfiguration installedConfiguration = ConfigurationManager
|
||||
.getConfigInstance();
|
||||
if (installedConfiguration instanceof ConcurrentCompositeConfiguration) {
|
||||
ConcurrentCompositeConfiguration configInstance = (ConcurrentCompositeConfiguration) installedConfiguration;
|
||||
configInstance.addConfiguration(config);
|
||||
}
|
||||
else {
|
||||
installedConfiguration.append(config);
|
||||
if (!(installedConfiguration instanceof AggregatedConfiguration)) {
|
||||
log.warn(
|
||||
"Appending a configuration to an existing non-aggregated installed configuration will have no effect");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
ConfigurationManager.install(config);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setStatic(Class<?> type, String name, Object value) {
|
||||
// Hack a private static field
|
||||
Field field = ReflectionUtils.findField(type, name);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
ReflectionUtils.setField(field, null, value);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(Health.class)
|
||||
protected static class ArchaiusEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnAvailableEndpoint
|
||||
protected ArchaiusEndpoint archaiusEndpoint() {
|
||||
return new ArchaiusEndpoint();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(value = "archaius.propagate.environmentChangedEvent",
|
||||
matchIfMissing = true)
|
||||
@ConditionalOnClass(EnvironmentChangeEvent.class)
|
||||
protected static class PropagateEventsConfiguration
|
||||
implements ApplicationListener<EnvironmentChangeEvent> {
|
||||
|
||||
@Autowired
|
||||
private Environment env;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(EnvironmentChangeEvent event) {
|
||||
AbstractConfiguration manager = ConfigurationManager.getConfigInstance();
|
||||
for (String key : event.getKeys()) {
|
||||
for (ConfigurationListener listener : manager
|
||||
.getConfigurationListeners()) {
|
||||
Object source = event.getSource();
|
||||
// TODO: Handle add vs set vs delete?
|
||||
int type = AbstractConfiguration.EVENT_SET_PROPERTY;
|
||||
String value = this.env.getProperty(key);
|
||||
boolean beforeUpdate = false;
|
||||
listener.configurationChanged(new ConfigurationEvent(source, type,
|
||||
key, value, beforeUpdate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public final class ArchaiusDelegatingProxyUtils {
|
||||
|
||||
private ArchaiusDelegatingProxyUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code ApplicationContext} class name.
|
||||
*/
|
||||
public static String APPLICATION_CONTEXT = ApplicationContext.class.getName();
|
||||
|
||||
public static <T> T getNamedInstance(Class<T> type, String name) {
|
||||
ApplicationContext context = (ApplicationContext) ConfigurationManager
|
||||
.getConfigInstance().getProperty(APPLICATION_CONTEXT);
|
||||
return context != null && context.containsBean(name) ? context.getBean(name, type)
|
||||
: null;
|
||||
}
|
||||
|
||||
public static <T> T getInstanceWithPrefix(Class<T> type, String prefix) {
|
||||
String name = prefix + type.getSimpleName();
|
||||
return getNamedInstance(type, name);
|
||||
}
|
||||
|
||||
public static void addApplicationContext(ConfigurableApplicationContext context) {
|
||||
AbstractConfiguration config = ConfigurationManager.getConfigInstance();
|
||||
config.clearProperty(APPLICATION_CONTEXT);
|
||||
config.setProperty(APPLICATION_CONTEXT, context);
|
||||
}
|
||||
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.apache.commons.configuration.Configuration;
|
||||
import org.apache.commons.configuration.EnvironmentConfiguration;
|
||||
import org.apache.commons.configuration.SystemConfiguration;
|
||||
|
||||
import org.springframework.boot.actuate.endpoint.annotation.Endpoint;
|
||||
import org.springframework.boot.actuate.endpoint.annotation.ReadOperation;
|
||||
|
||||
/**
|
||||
* An actuator endpoint that returns Archaius configuration.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@Endpoint(id = "archaius")
|
||||
public class ArchaiusEndpoint {
|
||||
|
||||
@ReadOperation
|
||||
public Map<String, Object> invoke() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
AbstractConfiguration config = ConfigurationManager.getConfigInstance();
|
||||
if (config instanceof ConcurrentCompositeConfiguration) {
|
||||
ConcurrentCompositeConfiguration composite = (ConcurrentCompositeConfiguration) config;
|
||||
for (Configuration item : composite.getConfigurations()) {
|
||||
append(map, item);
|
||||
}
|
||||
}
|
||||
else {
|
||||
append(map, config);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void append(Map<String, Object> map, Configuration config) {
|
||||
if (config instanceof ConfigurableEnvironmentConfiguration) {
|
||||
return;
|
||||
}
|
||||
if (config instanceof SystemConfiguration) {
|
||||
return;
|
||||
}
|
||||
if (config instanceof EnvironmentConfiguration) {
|
||||
return;
|
||||
}
|
||||
for (Iterator<String> iter = config.getKeys(); iter.hasNext();) {
|
||||
String key = iter.next();
|
||||
map.put(key, config.getProperty(key));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
/**
|
||||
* EnvironmentConfiguration wrapper class providing further configuration possibilities.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class ConfigurableEnvironmentConfiguration extends AbstractConfiguration {
|
||||
|
||||
private final ConfigurableEnvironment environment;
|
||||
|
||||
public ConfigurableEnvironmentConfiguration(ConfigurableEnvironment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addPropertyDirect(String key, Object value) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return !getKeys().hasNext(); // TODO: find a better way to do this
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(String key) {
|
||||
return this.environment.containsProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String key) {
|
||||
return this.environment.getProperty(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> getKeys() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Map.Entry<String, PropertySource<?>> entry : getPropertySources()
|
||||
.entrySet()) {
|
||||
PropertySource<?> source = entry.getValue();
|
||||
if (source instanceof EnumerablePropertySource) {
|
||||
EnumerablePropertySource<?> enumerable = (EnumerablePropertySource<?>) source;
|
||||
for (String name : enumerable.getPropertyNames()) {
|
||||
result.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.iterator();
|
||||
}
|
||||
|
||||
private Map<String, PropertySource<?>> getPropertySources() {
|
||||
Map<String, PropertySource<?>> map = new LinkedHashMap<>();
|
||||
MutablePropertySources sources = (this.environment != null
|
||||
? this.environment.getPropertySources()
|
||||
: new StandardEnvironment().getPropertySources());
|
||||
for (PropertySource<?> source : sources) {
|
||||
extract("", map, source);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private void extract(String root, Map<String, PropertySource<?>> map,
|
||||
PropertySource<?> source) {
|
||||
if (source instanceof CompositePropertySource) {
|
||||
for (PropertySource<?> nest : ((CompositePropertySource) source)
|
||||
.getPropertySources()) {
|
||||
extract(source.getName() + ":", map, nest);
|
||||
}
|
||||
}
|
||||
else {
|
||||
map.put(root + source.getName(), source);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"properties": [
|
||||
{
|
||||
"defaultValue": "true",
|
||||
"name": "archaius.propagate.environmentChangedEvent",
|
||||
"description": "Propagates EnvironmentChanged events to Archaius ConfigurationManager.",
|
||||
"type": "java.lang.Boolean"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.netflix.archaius.ArchaiusAutoConfiguration
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DynamicPropertyFactory;
|
||||
import com.netflix.config.DynamicStringProperty;
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ArchaiusAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context;
|
||||
|
||||
private Object propertyValue;
|
||||
|
||||
@After
|
||||
public void close() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationCreated() {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
ArchaiusAutoConfiguration.class);
|
||||
AbstractConfiguration config = this.context
|
||||
.getBean(ConfigurableEnvironmentConfiguration.class);
|
||||
assertThat(config.getString("java.io.tmpdir")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void environmentChangeEventPropagated() {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
ArchaiusAutoConfiguration.class);
|
||||
ConfigurationManager.getConfigInstance().addConfigurationListener(event -> {
|
||||
if (event.getPropertyName().equals("my.prop")) {
|
||||
ArchaiusAutoConfigurationTests.this.propertyValue = event
|
||||
.getPropertyValue();
|
||||
}
|
||||
});
|
||||
TestPropertyValues.of("my.prop=my.newval").applyTo(this.context);
|
||||
this.context.publishEvent(
|
||||
new EnvironmentChangeEvent(Collections.singleton("my.prop")));
|
||||
assertThat(this.propertyValue).isEqualTo("my.newval");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationWithoutExternalConfigurations() throws Exception {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
ArchaiusAutoConfiguration.class);
|
||||
DynamicStringProperty dbProperty = DynamicPropertyFactory.getInstance()
|
||||
.getStringProperty("db.property", null);
|
||||
DynamicStringProperty staticProperty = DynamicPropertyFactory.getInstance()
|
||||
.getStringProperty("archaius.file.property", null);
|
||||
|
||||
assertThat(dbProperty.getValue()).isNull();
|
||||
assertThat(staticProperty.getValue()).isNotNull();
|
||||
assertThat(staticProperty.getValue()).isEqualTo("Static config file property");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configurationWithInjectedConfiguration() throws Exception {
|
||||
this.context = new AnnotationConfigApplicationContext(
|
||||
ArchaiusAutoConfiguration.class, TestArchaiusExternalConfiguration.class);
|
||||
DynamicStringProperty dbProperty = DynamicPropertyFactory.getInstance()
|
||||
.getStringProperty("db.property", null);
|
||||
DynamicStringProperty secondDbProperty = DynamicPropertyFactory.getInstance()
|
||||
.getStringProperty("db.second.property", null);
|
||||
DynamicStringProperty staticProperty = DynamicPropertyFactory.getInstance()
|
||||
.getStringProperty("archaius.file.property", null);
|
||||
|
||||
assertThat(dbProperty.getValue()).isNotNull();
|
||||
assertThat(secondDbProperty.getValue()).isNotNull();
|
||||
assertThat(staticProperty.getValue()).isNotNull();
|
||||
assertThat(dbProperty.getValue()).isEqualTo("this is a db property");
|
||||
assertThat(secondDbProperty.getValue()).isEqualTo("this is another db property");
|
||||
assertThat(staticProperty.getValue()).isEqualTo("Static config file property");
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.config.ConcurrentCompositeConfiguration;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ArchaiusEndpointTests {
|
||||
|
||||
private ArchaiusEndpoint endpoint = new ArchaiusEndpoint();
|
||||
|
||||
@Test
|
||||
public void detectsPropertiesWhenSet() {
|
||||
ConfigurationManager.getConfigInstance().setProperty("foo", "bar");
|
||||
assertThat(this.endpoint.invoke().containsKey("foo")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesNotIncludeSpringEnvironment() {
|
||||
ConcurrentCompositeConfiguration composite = new ConcurrentCompositeConfiguration(
|
||||
ConfigurationManager.getConfigInstance());
|
||||
ConfigurableEnvironmentConfiguration config = new ConfigurableEnvironmentConfiguration(
|
||||
new StandardEnvironment());
|
||||
assertThat(config.containsKey("user.dir")).isTrue();
|
||||
composite.addConfiguration(config);
|
||||
ConfigurationManager.getConfigInstance().setProperty("foo", "bar");
|
||||
Map<String, Object> map = this.endpoint.invoke();
|
||||
assertThat(map.containsKey("foo")).isTrue();
|
||||
assertThat(map.containsKey("user.dir")).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import com.netflix.config.DynamicProperty;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Liang Yong
|
||||
*/
|
||||
|
||||
@SpringBootTest(classes = LazyLoadConfigurationTests.TestConfig.class,
|
||||
properties = { "client.ribbon.listOfServers=foo.com,bar.com",
|
||||
"spring.main.lazy-initialization=true" })
|
||||
public class LazyLoadConfigurationTests {
|
||||
|
||||
@Test
|
||||
public void enableLazyInitialization() {
|
||||
DynamicProperty instance = DynamicProperty
|
||||
.getInstance("client.ribbon.listOfServers");
|
||||
assertThat(instance.getString()).isEqualTo("foo.com,bar.com");
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
static class TestConfig {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.archaius;
|
||||
|
||||
import com.netflix.config.ConcurrentMapConfiguration;
|
||||
import org.apache.commons.configuration.AbstractConfiguration;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Alexandru-George Burghelea
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class TestArchaiusExternalConfiguration {
|
||||
|
||||
@Bean
|
||||
@Qualifier("dynamicConfiguration")
|
||||
public AbstractConfiguration createDynamicConfiguration() {
|
||||
ConcurrentMapConfiguration config = new ConcurrentMapConfiguration();
|
||||
config.addProperty("db.property", "this is a db property");
|
||||
config.addProperty("db.second.property", "this is another db property");
|
||||
return config;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
archaius.file.property=Static config file property
|
||||
db.second.property=It should be overridden
|
||||
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-concurrency-limits</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Netflix Concurrency Limits</name>
|
||||
<url>https://projects.spring.io/spring-cloud/</url>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.netflix.concurrency-limits</groupId>
|
||||
<artifactId>concurrency-limits-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.concurrency-limits</groupId>
|
||||
<artifactId>concurrency-limits-servlet</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!--<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.micrometer;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.netflix.concurrency.limits.MetricRegistry;
|
||||
import io.micrometer.core.instrument.DistributionSummary;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.Tags;
|
||||
|
||||
/**
|
||||
* A Micrometer-specific {@link MetricRegistry} implementation.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class MicrometerMetricRegistry implements MetricRegistry {
|
||||
|
||||
private final MeterRegistry meterRegistry;
|
||||
|
||||
// TODO: baseId?
|
||||
|
||||
public MicrometerMetricRegistry(MeterRegistry meterRegistry) {
|
||||
this.meterRegistry = meterRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SampleListener registerDistribution(String id, String... tagNameValuePairs) {
|
||||
DistributionSummary summary = this.meterRegistry.summary(id, tagNameValuePairs);
|
||||
return value -> summary.record(value.longValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerGauge(String id, Supplier<Number> supplier,
|
||||
String... tagNameValuePairs) {
|
||||
this.meterRegistry.gauge(id, Tags.of(tagNameValuePairs), supplier.get());
|
||||
}
|
||||
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.reactive;
|
||||
|
||||
import com.netflix.concurrency.limits.Limiter;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
import org.springframework.web.server.WebFilterChain;
|
||||
|
||||
/**
|
||||
* A {@link WebFilter} implementation providing the possibility to use Netflix
|
||||
* {@link Limiter} to handle requests.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConcurrencyLimitsWebFilter implements WebFilter {
|
||||
|
||||
private final Limiter<ServerWebExchange> limiter;
|
||||
|
||||
public ConcurrencyLimitsWebFilter(Limiter<ServerWebExchange> limiter) {
|
||||
this.limiter = limiter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
|
||||
return limiter.acquire(exchange)
|
||||
.map(listener -> chain.filter(exchange)
|
||||
.doOnSuccess(v -> listener.onSuccess())
|
||||
.doOnError(throwable -> listener.onIgnore()))
|
||||
.orElseGet(() -> {
|
||||
exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
|
||||
// TODO: set body
|
||||
return exchange.getResponse().setComplete();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.reactive;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.netflix.concurrency.limits.Limiter;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.server.WebFilter;
|
||||
|
||||
/**
|
||||
* Reactive autoconfiguration class for registering Netflix {@link Limiter} bean.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.REACTIVE)
|
||||
@ConditionalOnClass({ WebFilter.class, Mono.class })
|
||||
public class ReactiveConcurrencyLimitsAutoConfiguration {
|
||||
|
||||
private final ObjectProvider<Consumer<ServerWebExchangeLimiterBuilder>> configurerProvider;
|
||||
|
||||
public ReactiveConcurrencyLimitsAutoConfiguration(
|
||||
ObjectProvider<Consumer<ServerWebExchangeLimiterBuilder>> configurerProvider) {
|
||||
this.configurerProvider = configurerProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Limiter<ServerWebExchange> webfluxLimiter() {
|
||||
ServerWebExchangeLimiterBuilder builder = new ServerWebExchangeLimiterBuilder();
|
||||
|
||||
this.configurerProvider.ifAvailable(consumer -> consumer.accept(builder));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConcurrencyLimitsWebFilter concurrencyLimitsWebFilter(
|
||||
Limiter<ServerWebExchange> limiter) {
|
||||
return new ConcurrencyLimitsWebFilter(limiter);
|
||||
}
|
||||
|
||||
}
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.reactive;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.netflix.concurrency.limits.limiter.AbstractPartitionedLimiter;
|
||||
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Builder for ServerWebExchange Limiter.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class ServerWebExchangeLimiterBuilder extends
|
||||
AbstractPartitionedLimiter.Builder<ServerWebExchangeLimiterBuilder, ServerWebExchange> {
|
||||
|
||||
/**
|
||||
* Partition the limit by header.
|
||||
* @param name header name
|
||||
* @return Chainable builder
|
||||
*/
|
||||
public ServerWebExchangeLimiterBuilder partitionByHeader(String name) {
|
||||
return partitionResolver(
|
||||
exchange -> exchange.getRequest().getHeaders().getFirst(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the limit by {@link Principal}. Percentages of the limit are partitioned
|
||||
* to named groups. Group membership is derived from the provided mapping function.
|
||||
* @param principalToGroup Mapping function from {@link Principal} to a named group.
|
||||
* @param configurer Configuration function though which group percentages may be
|
||||
* specified Unspecified group values may only use excess capacity.
|
||||
* @return Chainable builder
|
||||
*/
|
||||
/*
|
||||
* public ServerWebExchangeLimiterBuilder partitionByUserPrincipal(Function<Principal,
|
||||
* String> principalToGroup,
|
||||
* Consumer<LookupPartitionStrategy.Builder<ServerWebExchange>> configurer) { return
|
||||
* partitionResolver( exchange ->
|
||||
* Optional.ofNullable(request.getUserPrincipal()).map(principalToGroup).orElse(null),
|
||||
* configurer); }
|
||||
*/
|
||||
|
||||
/**
|
||||
* Partition the limit by request attribute.
|
||||
* @param name attribute name
|
||||
* @return Chainable builder
|
||||
*/
|
||||
public ServerWebExchangeLimiterBuilder partitionByAttribute(String name) {
|
||||
return partitionResolver(exchange -> exchange.getAttribute(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the limit by request parameter.
|
||||
* @param name parameter name
|
||||
* @return Chainable builder
|
||||
*/
|
||||
public ServerWebExchangeLimiterBuilder partitionByParameter(String name) {
|
||||
return partitionResolver(
|
||||
exchange -> exchange.getRequest().getQueryParams().getFirst(name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Partition the limit by the full path. Percentages of the limit are partitioned to
|
||||
* named groups. Group membership is derived from the provided mapping function.
|
||||
* @param pathToGroup Mapping function from full path to a named group.
|
||||
* @return Chainable builder
|
||||
*/
|
||||
public ServerWebExchangeLimiterBuilder partitionByPathInfo(
|
||||
Function<String, String> pathToGroup) {
|
||||
return partitionResolver(exchange -> {
|
||||
// TODO: pathWithinApplication?
|
||||
String path = exchange.getRequest().getPath().contextPath().value();
|
||||
return Optional.ofNullable(path).map(pathToGroup).orElse(null);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ServerWebExchangeLimiterBuilder self() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.web;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.netflix.concurrency.limits.Limiter;
|
||||
import com.netflix.concurrency.limits.Limiter.Listener;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
|
||||
/**
|
||||
* A {@link HandlerInterceptor} implementation providing the possibility to use Netflix
|
||||
* {@link Limiter} to handle requests.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConcurrencyLimitsHandlerInterceptor implements HandlerInterceptor {
|
||||
|
||||
private final Limiter<HttpServletRequest> limiter;
|
||||
|
||||
public ConcurrencyLimitsHandlerInterceptor(Limiter<HttpServletRequest> limiter) {
|
||||
this.limiter = limiter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler) throws Exception {
|
||||
Optional<Listener> listener = limiter.acquire(request);
|
||||
if (listener.isPresent()) {
|
||||
request.setAttribute("concurrency_limiter_listener", listener.get());
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
// TODO: headers with information?
|
||||
/*
|
||||
* response.sendError(HttpStatus.TOO_MANY_REQUESTS.value());
|
||||
* response.getWriter().print("Concurrency limit exceeded");
|
||||
*/
|
||||
response.sendError(HttpStatus.TOO_MANY_REQUESTS.value(),
|
||||
"Concurrency limit exceeded");
|
||||
}
|
||||
catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postHandle(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, ModelAndView modelAndView) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception ex) throws Exception {
|
||||
Listener listener = (Listener) request
|
||||
.getAttribute("concurrency_limiter_listener");
|
||||
if (listener != null) {
|
||||
if (ex != null) {
|
||||
listener.onIgnore();
|
||||
}
|
||||
else {
|
||||
listener.onSuccess();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.web;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.netflix.concurrency.limits.Limiter;
|
||||
import com.netflix.concurrency.limits.servlet.ServletLimiterBuilder;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* MVC autoconfiguration class for registering Netflix {@link Limiter} bean.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @deprecated to be removed in 3.0.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnWebApplication(type = Type.SERVLET)
|
||||
@ConditionalOnClass({ HttpServletRequest.class, HandlerInterceptor.class })
|
||||
@Deprecated
|
||||
public class MvcConcurrencyLimitsAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
private final ObjectProvider<Consumer<ServletLimiterBuilder>> configurerProvider;
|
||||
|
||||
public MvcConcurrencyLimitsAutoConfiguration(
|
||||
ObjectProvider<Consumer<ServletLimiterBuilder>> configurerProvider) {
|
||||
this.configurerProvider = configurerProvider;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public Limiter<HttpServletRequest> servletLimiter() {
|
||||
ServletLimiterBuilder builder = new ServletLimiterBuilder();
|
||||
|
||||
this.configurerProvider.ifAvailable(consumer -> consumer.accept(builder));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
protected static class HandlerInterceptorConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@Autowired
|
||||
private Limiter<HttpServletRequest> limiter;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new ConcurrencyLimitsHandlerInterceptor(limiter));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.netflix.concurrency.limits.reactive.ReactiveConcurrencyLimitsAutoConfiguration,\
|
||||
org.springframework.cloud.netflix.concurrency.limits.web.MvcConcurrencyLimitsAutoConfiguration
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.micrometer;
|
||||
|
||||
import io.micrometer.core.instrument.Gauge;
|
||||
import io.micrometer.core.instrument.MeterRegistry;
|
||||
import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class MicrometerMetricRegistryTests {
|
||||
|
||||
@Test
|
||||
public void testGuage() {
|
||||
MeterRegistry registry = new SimpleMeterRegistry();
|
||||
MicrometerMetricRegistry metricRegistry = new MicrometerMetricRegistry(registry);
|
||||
|
||||
metricRegistry.registerGauge("bar", () -> 10);
|
||||
|
||||
Gauge bar = registry.get("bar").gauge();
|
||||
|
||||
assertThat(bar.value()).isEqualTo(10.0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // FIXME: micrometer doesn't allow recreating a gauge
|
||||
public void testUnregister() {
|
||||
MeterRegistry registry = new SimpleMeterRegistry();
|
||||
MicrometerMetricRegistry metricRegistry = new MicrometerMetricRegistry(registry);
|
||||
|
||||
metricRegistry.registerGauge("bar", () -> 10);
|
||||
metricRegistry.registerGauge("bar", () -> 20);
|
||||
|
||||
Gauge bar = registry.get("bar").gauge();
|
||||
|
||||
assertThat(bar.value()).isEqualTo(20.0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.reactive;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.netflix.concurrency.limits.limit.FixedLimit;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.netflix.concurrency.limits.test.AbstractConcurrencyLimitsTests;
|
||||
import org.springframework.cloud.test.ClassPathExclusions;
|
||||
import org.springframework.cloud.test.ModifiedClassPathRunner;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@RunWith(ModifiedClassPathRunner.class)
|
||||
@ClassPathExclusions({ "spring-boot-starter-tomcat-*", "tomcat-embed-*" })
|
||||
public class ConcurrencyLimitsWebFilterTests extends AbstractConcurrencyLimitsTests {
|
||||
|
||||
private int port;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
port = SocketUtils.findAvailableTcpPort();
|
||||
client = WebClient.create("http://localhost:" + port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("Duplicates")
|
||||
public void webFilterWorks() {
|
||||
|
||||
try (ConfigurableApplicationContext context = new SpringApplicationBuilder()
|
||||
.properties("server.port=" + port,
|
||||
"spring.main.web-application-type=reactive")
|
||||
.sources(TestConfig.class).run()) {
|
||||
|
||||
assertLimiter(client);
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@Import(HelloControllerConfiguration.class)
|
||||
protected static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public Consumer<ServerWebExchangeLimiterBuilder> limiterBuilderConfigurer() {
|
||||
return limiterBuilder -> limiterBuilder.limit(FixedLimit.of(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.test;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
import reactor.util.function.Tuple2;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class AbstractConcurrencyLimitsTests {
|
||||
|
||||
protected WebClient client;
|
||||
|
||||
protected void assertLimiter(WebClient client) {
|
||||
// TODO: assert the body
|
||||
Flux<Tuple2<String, HttpStatus>> flux = Flux.range(1, 100)
|
||||
.flatMap(integer -> client.get().uri("/").exchange(), 4)
|
||||
// .log("reqs", Level.INFO)
|
||||
.flatMap(response -> response.bodyToMono(String.class).defaultIfEmpty("")
|
||||
/* .log("body2mono", Level.INFO) */
|
||||
.zipWith(Mono.just(response.statusCode())));
|
||||
|
||||
Responses responses = new Responses();
|
||||
StepVerifier.create(flux).thenConsumeWhile(response -> true, response -> {
|
||||
HttpStatus status = response.getT2();
|
||||
if (status.equals(HttpStatus.OK)) {
|
||||
responses.success.incrementAndGet();
|
||||
}
|
||||
else if (status.equals(HttpStatus.TOO_MANY_REQUESTS)) {
|
||||
responses.tooManyReqs.incrementAndGet();
|
||||
String body = response.getT1();
|
||||
// TODO: body from handler isn't coming thru
|
||||
// assertThat(body).isEqualTo("Concurrency limit exceeded");
|
||||
}
|
||||
else {
|
||||
responses.other.incrementAndGet();
|
||||
}
|
||||
}).verifyComplete();
|
||||
|
||||
System.out.println("Responses: " + responses);
|
||||
|
||||
assertThat(responses.other).hasValue(0);
|
||||
assertThat(responses.tooManyReqs).hasValueGreaterThanOrEqualTo(1);
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@RestController
|
||||
protected static class HelloControllerConfiguration {
|
||||
|
||||
@GetMapping
|
||||
public String get() {
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.test;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.springframework.core.style.ToStringCreator;
|
||||
|
||||
public class Responses {
|
||||
|
||||
public AtomicInteger success = new AtomicInteger(0);
|
||||
|
||||
public AtomicInteger tooManyReqs = new AtomicInteger(0);
|
||||
|
||||
public AtomicInteger other = new AtomicInteger(0);
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new ToStringCreator(this).append("success", success)
|
||||
.append("tooManyReqs", tooManyReqs).append("other", other).toString();
|
||||
}
|
||||
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.concurrency.limits.web;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.netflix.concurrency.limits.limit.FixedLimit;
|
||||
import com.netflix.concurrency.limits.servlet.ServletLimiterBuilder;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.cloud.netflix.concurrency.limits.test.AbstractConcurrencyLimitsTests;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.springframework.boot.test.context.SpringBootTest.WebEnvironment.RANDOM_PORT;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(properties = "logging.level.reactor.netty=DEBUG",
|
||||
webEnvironment = RANDOM_PORT)
|
||||
public class ConcurrencyLimitsHandlerInterceptorTests
|
||||
extends AbstractConcurrencyLimitsTests {
|
||||
|
||||
@LocalServerPort
|
||||
public int port;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
client = WebClient.create("http://localhost:" + port);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void handlerInterceptorWorks() {
|
||||
assertLimiter(client);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@Import(HelloControllerConfiguration.class)
|
||||
protected static class TestConfig {
|
||||
|
||||
@Bean
|
||||
public Consumer<ServletLimiterBuilder> limiterBuilderConfigurer() {
|
||||
return servletLimiterBuilder -> servletLimiterBuilder.limit(FixedLimit.of(1));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-core</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Netflix Core - Deprecated</name>
|
||||
<description>Deprecated Spring Cloud Netflix Core - will be removed. Please use spring-cloud-netflix-hystrix instead.</description>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>java8plus</id>
|
||||
<activation>
|
||||
<jdk>[1.8,2.0)</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<compilerArgs>
|
||||
<arg>-parameters</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2018-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.core;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 2.1.0
|
||||
* @deprecated Module spring-cloud-netflix-core is deprecated as of 2.1.0, use
|
||||
* spring-cloud-netflix-hystrix instead.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Deprecated
|
||||
public class CoreAutoConfiguration {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(CoreAutoConfiguration.class);
|
||||
|
||||
public CoreAutoConfiguration() {
|
||||
LOG.warn(
|
||||
"This module is deprecated. It will be removed in the next major release. "
|
||||
+ "Please use spring-cloud-netflix-hystrix instead.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.netflix.core.CoreAutoConfiguration
|
||||
@@ -5,17 +5,24 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.3.6.BUILD-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-netflix-dependencies</name>
|
||||
<description>Spring Cloud Netflix Dependencies</description>
|
||||
<properties>
|
||||
<eureka.version>1.10.16</eureka.version>
|
||||
<xstream.version>1.4.18</xstream.version>
|
||||
<archaius.version>0.7.7</archaius.version>
|
||||
<concurrency-limits.version>0.1.12</concurrency-limits.version>
|
||||
<eureka.version>1.10.14</eureka.version>
|
||||
<eventbus.version>0.3.0</eventbus.version>
|
||||
<hystrix.version>1.5.18</hystrix.version>
|
||||
<ribbon.version>2.3.0</ribbon.version>
|
||||
<servo.version>0.12.21</servo.version>
|
||||
<zuul.version>1.3.1</zuul.version>
|
||||
<turbine.version>1.0.0</turbine.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -24,6 +31,16 @@
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-archaius</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
|
||||
@@ -34,20 +51,132 @@
|
||||
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-turbine-stream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-core</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix-stream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-sidecar</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-turbine</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-turbine-stream</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-zuul</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-ribbon</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.netflix-commons</groupId>
|
||||
<artifactId>netflix-commons-util</artifactId>
|
||||
<version>0.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
<version>${archaius.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.concurrency-limits</groupId>
|
||||
<artifactId>concurrency-limits-core</artifactId>
|
||||
<version>${concurrency-limits.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.concurrency-limits</groupId>
|
||||
<artifactId>concurrency-limits-servlet</artifactId>
|
||||
<version>${concurrency-limits.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.servo</groupId>
|
||||
<artifactId>servo-core</artifactId>
|
||||
<version>${servo.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
<artifactId>eureka-client</artifactId>
|
||||
<version>${eureka.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.github.vlsi.compactmap</groupId>
|
||||
<artifactId>compactmap</artifactId>
|
||||
@@ -75,10 +204,6 @@
|
||||
<artifactId>eureka-core</artifactId>
|
||||
<version>${eureka.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
@@ -111,18 +236,138 @@
|
||||
<artifactId>*</artifactId>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
</exclusion>
|
||||
<!-- TODO: Move back to Eureka dependency when 1.10.17 released -->
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-core</artifactId>
|
||||
<version>${hystrix.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- TODO: Move back to Eureka dependency when 1.10.17 released -->
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<version>${xstream.version}</version>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-serialization</artifactId>
|
||||
<version>${hystrix.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-metrics-event-stream</artifactId>
|
||||
<version>${hystrix.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.hystrix</groupId>
|
||||
<artifactId>hystrix-javanica</artifactId>
|
||||
<version>${hystrix.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>jsr305</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon</artifactId>
|
||||
<version>${ribbon.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-logging</groupId>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-core</artifactId>
|
||||
<version>${ribbon.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-httpclient</artifactId>
|
||||
<version>${ribbon.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-eureka</artifactId>
|
||||
<version>${ribbon.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-loadbalancer</artifactId>
|
||||
<version>${ribbon.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.zuul</groupId>
|
||||
<artifactId>zuul-core</artifactId>
|
||||
<version>${zuul.version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>groovy-all</artifactId>
|
||||
<groupId>org.codehaus.groovy</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>mockito-all</artifactId>
|
||||
<groupId>org.mockito</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.netflix-commons</groupId>
|
||||
<artifactId>netflix-eventbus</artifactId>
|
||||
<version>${eventbus.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client-tls-tests</artifactId>
|
||||
@@ -93,22 +93,11 @@
|
||||
<version>1.68</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml</groupId>
|
||||
<artifactId>jaxb-impl</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<includes>
|
||||
<include>**/*Suite.java</include>
|
||||
</includes>
|
||||
<excludes>
|
||||
<exclude>**/*Test.java</exclude>
|
||||
<exclude>**/*Tests.java</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
+2
-12
@@ -46,7 +46,6 @@ public class AppRunner implements AutoCloseable {
|
||||
public void start() {
|
||||
if (app == null) {
|
||||
SpringApplicationBuilder builder = new SpringApplicationBuilder(appClass);
|
||||
builder.properties("spring.application.name=" + appClass.getName());
|
||||
builder.properties("spring.jmx.enabled=false");
|
||||
builder.properties(String.format("server.port=%d", availabeTcpPort()));
|
||||
builder.properties(props());
|
||||
@@ -73,16 +72,6 @@ public class AppRunner implements AutoCloseable {
|
||||
public void stop() {
|
||||
if (app != null) {
|
||||
app.stop();
|
||||
int attempts = 5;
|
||||
while (app.isRunning() && attempts > 0) {
|
||||
attempts = attempts - 1;
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
app = null;
|
||||
}
|
||||
}
|
||||
@@ -124,7 +113,8 @@ public class AppRunner implements AutoCloseable {
|
||||
}
|
||||
|
||||
private boolean tlsEnabled() {
|
||||
return app.getEnvironment().getProperty("server.ssl.enabled", Boolean.class, false);
|
||||
return app.getEnvironment().getProperty("server.ssl.enabled", Boolean.class,
|
||||
false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-121
@@ -20,22 +20,10 @@ import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.security.KeyStore;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
abstract class BaseCertTest {
|
||||
|
||||
private static final Log log = LogFactory.getLog(BaseCertTest.class);
|
||||
public abstract class BaseCertTest {
|
||||
|
||||
protected static final String KEY_STORE_PASSWORD = "test-key-store-password";
|
||||
|
||||
@@ -56,47 +44,8 @@ abstract class BaseCertTest {
|
||||
protected BaseCertTest() {
|
||||
}
|
||||
|
||||
static EurekaServerRunner startEurekaServer(Class config) {
|
||||
EurekaServerRunner server = new EurekaServerRunner(config);
|
||||
server.enableTls();
|
||||
server.setKeyStore(serverCert, KEY_STORE_PASSWORD, "server", KEY_PASSWORD);
|
||||
server.setTrustStore(caCert, KEY_STORE_PASSWORD);
|
||||
|
||||
server.start();
|
||||
return server;
|
||||
}
|
||||
|
||||
static void stopEurekaServer(EurekaServerRunner server) {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
static EurekaClientRunner startService(EurekaServerRunner server, Class config) {
|
||||
EurekaClientRunner service = new EurekaClientRunner(config, server, "testservice");
|
||||
enableTlsClient(service);
|
||||
service.start();
|
||||
return service;
|
||||
}
|
||||
|
||||
static void stopService(EurekaClientRunner service) {
|
||||
service.stop();
|
||||
}
|
||||
|
||||
static void enableTlsClient(EurekaClientRunner runner) {
|
||||
runner.enableTls();
|
||||
runner.setKeyStore(clientCert, KEY_STORE_PASSWORD, KEY_PASSWORD);
|
||||
runner.setTrustStore(caCert, KEY_STORE_PASSWORD);
|
||||
}
|
||||
|
||||
static void waitForRegistration(Supplier<EurekaClientRunner> clientSupplier) {
|
||||
try (EurekaClientRunner client = clientSupplier.get()) {
|
||||
enableTlsClient(client);
|
||||
client.start();
|
||||
client.waitServiceViaEureka(60);
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void createCertificates() throws Exception {
|
||||
@BeforeClass
|
||||
public static void createCertificates() throws Exception {
|
||||
KeyTool tool = new KeyTool();
|
||||
|
||||
KeyAndCert ca = tool.createCA("MyCA");
|
||||
@@ -114,79 +63,17 @@ abstract class BaseCertTest {
|
||||
wrongClientCert = saveKeyAndCert(wrongClient);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
static void afterClass() {
|
||||
log.info("Tests finished!");
|
||||
}
|
||||
|
||||
abstract EurekaClientRunner createEurekaClient();
|
||||
|
||||
/**
|
||||
* Already proved this in waitForRegistration(). Keep this Test to express test
|
||||
* purpose explicitly.
|
||||
*/
|
||||
@Test
|
||||
void clientCertCanWork() {
|
||||
}
|
||||
|
||||
@Test
|
||||
void noCertCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
client.disableTls();
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongCertCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(wrongClientCert);
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongPasswordCauseFailure() {
|
||||
EurekaClientRunner client = createEurekaClient();
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(clientCert, WRONG_PASSWORD, WRONG_PASSWORD);
|
||||
Assertions.assertThrows(BeanCreationException.class, () -> {
|
||||
client.start();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonExistKeyStoreCauseFailure() {
|
||||
EurekaClientRunner client = createEurekaClient();
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(new File("nonExistFile"));
|
||||
Assertions.assertThrows(BeanCreationException.class, () -> {
|
||||
client.start();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void wrongTrustStoreCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
enableTlsClient(client);
|
||||
client.setTrustStore(wrongCaCert);
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
private static File saveKeyAndCert(KeyAndCert keyCert) throws Exception {
|
||||
return saveKeyStore(keyCert.subject(), () -> keyCert.storeKeyAndCert(KEY_PASSWORD));
|
||||
return saveKeyStore(keyCert.subject(),
|
||||
() -> keyCert.storeKeyAndCert(KEY_PASSWORD));
|
||||
}
|
||||
|
||||
private static File saveCert(KeyAndCert keyCert) throws Exception {
|
||||
return saveKeyStore(keyCert.subject(), () -> keyCert.storeCert());
|
||||
}
|
||||
|
||||
private static File saveKeyStore(String prefix, KeyStoreSupplier func) throws Exception {
|
||||
private static File saveKeyStore(String prefix, KeyStoreSupplier func)
|
||||
throws Exception {
|
||||
File result = File.createTempFile(prefix, ".p12");
|
||||
result.deleteOnExit();
|
||||
|
||||
|
||||
-6
@@ -19,8 +19,6 @@ package org.springframework.cloud.netflix.eureka;
|
||||
import java.io.File;
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
|
||||
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
|
||||
public class EurekaClientRunner extends AppRunner {
|
||||
@@ -98,8 +96,4 @@ public class EurekaClientRunner extends AppRunner {
|
||||
return !discovery.getServices().isEmpty();
|
||||
}
|
||||
|
||||
public AbstractDiscoveryClientOptionalArgs<Void> discoveryClientOptionalArgs() {
|
||||
return this.getBean(AbstractDiscoveryClientOptionalArgs.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-33
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Suite;
|
||||
|
||||
/**
|
||||
* We need to use a suite cause we need to first run all the Eureka Servers, then close
|
||||
* all of them. We can't run one EurekaServer, close it and then run another one, cause
|
||||
* Eureka is using static executor services that are shutdown when we close a context.
|
||||
* That means that when the new context starts we will fail cause the executor service is
|
||||
* already shutdown.
|
||||
*/
|
||||
@RunWith(Suite.class)
|
||||
@Suite.SuiteClasses({ EurekaClientTest.class, RestTemplateEurekaClientTest.class })
|
||||
public class EurekaClientSuite {
|
||||
|
||||
}
|
||||
+109
-18
@@ -16,11 +16,13 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import com.netflix.discovery.DiscoveryClient;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import java.io.File;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
|
||||
@@ -29,28 +31,117 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class EurekaClientTest extends BaseCertTest {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EurekaClientTest.class);
|
||||
private static EurekaServerRunner server;
|
||||
|
||||
static EurekaServerRunner server;
|
||||
private static EurekaClientRunner service;
|
||||
|
||||
static EurekaClientRunner service;
|
||||
|
||||
@BeforeAll
|
||||
@BeforeClass
|
||||
public static void setupAll() {
|
||||
server = startEurekaServer(EurekaClientTest.TestEurekaServer.class);
|
||||
service = startService(server, EurekaClientTest.TestApp.class);
|
||||
// Will use Jersey
|
||||
assertThat(service.discoveryClientOptionalArgs())
|
||||
.isInstanceOf(DiscoveryClient.DiscoveryClientOptionalArgs.class);
|
||||
log.info("Successfully asserted that Jersey will be used");
|
||||
waitForRegistration(() -> new EurekaClientTest().createEurekaClient());
|
||||
startEurekaServer();
|
||||
startService();
|
||||
waitForRegistration();
|
||||
}
|
||||
|
||||
@Override
|
||||
EurekaClientRunner createEurekaClient() {
|
||||
@AfterClass
|
||||
public static void tearDownAll() {
|
||||
stopService();
|
||||
stopEurekaServer();
|
||||
}
|
||||
|
||||
private static void startEurekaServer() {
|
||||
server = new EurekaServerRunner(TestEurekaServer.class);
|
||||
server.enableTls();
|
||||
server.setKeyStore(serverCert, KEY_STORE_PASSWORD, "server", KEY_PASSWORD);
|
||||
server.setTrustStore(caCert, KEY_STORE_PASSWORD);
|
||||
|
||||
server.start();
|
||||
}
|
||||
|
||||
private static void stopEurekaServer() {
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private static void startService() {
|
||||
service = new EurekaClientRunner(TestApp.class, server, "testservice");
|
||||
enableTlsClient(service);
|
||||
service.start();
|
||||
}
|
||||
|
||||
private static void stopService() {
|
||||
service.stop();
|
||||
}
|
||||
|
||||
private static void waitForRegistration() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
enableTlsClient(client);
|
||||
client.start();
|
||||
client.waitServiceViaEureka(60);
|
||||
}
|
||||
}
|
||||
|
||||
private static EurekaClientRunner createEurekaClient() {
|
||||
return new EurekaClientRunner(TestApp.class, server);
|
||||
}
|
||||
|
||||
private static void enableTlsClient(EurekaClientRunner runner) {
|
||||
runner.enableTls();
|
||||
runner.setKeyStore(clientCert, KEY_STORE_PASSWORD, KEY_PASSWORD);
|
||||
runner.setTrustStore(caCert, KEY_STORE_PASSWORD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Already proved this in waitForRegistration(). Keep this Test to express test
|
||||
* purpose explicitly.
|
||||
*/
|
||||
@Test
|
||||
public void clientCertCanWork() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void noCertCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
client.disableTls();
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongCertCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(wrongClientCert);
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void wrongPasswordCauseFailure() {
|
||||
EurekaClientRunner client = createEurekaClient();
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(clientCert, WRONG_PASSWORD, WRONG_PASSWORD);
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void nonExistKeyStoreCauseFailure() {
|
||||
EurekaClientRunner client = createEurekaClient();
|
||||
enableTlsClient(client);
|
||||
client.setKeyStore(new File("nonExistFile"));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongTrustStoreCannotWork() {
|
||||
try (EurekaClientRunner client = createEurekaClient()) {
|
||||
enableTlsClient(client);
|
||||
client.setTrustStore(wrongCaCert);
|
||||
client.start();
|
||||
assertThat(client.foundServiceViaEureka()).isFalse();
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
public static class TestApp {
|
||||
|
||||
+2
-1
@@ -34,7 +34,8 @@ public class EurekaServerRunner extends AppRunner {
|
||||
property("server.ssl.client-auth", "need");
|
||||
}
|
||||
|
||||
public void setKeyStore(File keyStore, String keyStorePassword, String key, String keyPassword) {
|
||||
public void setKeyStore(File keyStore, String keyStorePassword, String key,
|
||||
String keyPassword) {
|
||||
property("server.ssl.key-store", pathOf(keyStore));
|
||||
property("server.ssl.key-store-type", "PKCS12");
|
||||
property("server.ssl.key-store-password", keyStorePassword);
|
||||
|
||||
+2
-1
@@ -70,7 +70,8 @@ public class KeyAndCert {
|
||||
KeyStore result = KeyStore.getInstance("PKCS12");
|
||||
result.load(null);
|
||||
|
||||
result.setKeyEntry(subject(), keyPair.getPrivate(), keyPassword.toCharArray(), certChain());
|
||||
result.setKeyEntry(subject(), keyPair.getPrivate(), keyPassword.toCharArray(),
|
||||
certChain());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+28
-15
@@ -50,12 +50,15 @@ public class KeyTool {
|
||||
return new KeyAndCert(keyPair, certificate);
|
||||
}
|
||||
|
||||
public KeyAndCert signCertificate(String subject, KeyAndCert signer) throws Exception {
|
||||
public KeyAndCert signCertificate(String subject, KeyAndCert signer)
|
||||
throws Exception {
|
||||
return signCertificate(createKeyPair(), subject, signer);
|
||||
}
|
||||
|
||||
public KeyAndCert signCertificate(KeyPair keyPair, String subject, KeyAndCert signer) throws Exception {
|
||||
X509Certificate certificate = createCert(keyPair.getPublic(), signer.privateKey(), signer.subject(), subject);
|
||||
public KeyAndCert signCertificate(KeyPair keyPair, String subject, KeyAndCert signer)
|
||||
throws Exception {
|
||||
X509Certificate certificate = createCert(keyPair.getPublic(), signer.privateKey(),
|
||||
signer.subject(), subject);
|
||||
KeyAndCert result = new KeyAndCert(keyPair, certificate);
|
||||
|
||||
return result;
|
||||
@@ -73,25 +76,32 @@ public class KeyTool {
|
||||
|
||||
public X509Certificate createCert(KeyPair keyPair, String ca) throws Exception {
|
||||
JcaX509v3CertificateBuilder builder = certBuilder(keyPair.getPublic(), ca, ca);
|
||||
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
|
||||
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
|
||||
builder.addExtension(Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.keyCertSign));
|
||||
builder.addExtension(Extension.basicConstraints, false,
|
||||
new BasicConstraints(true));
|
||||
|
||||
return signCert(builder, keyPair.getPrivate());
|
||||
}
|
||||
|
||||
public X509Certificate createCert(PublicKey publicKey, PrivateKey privateKey, String issuer, String subject)
|
||||
throws Exception {
|
||||
public X509Certificate createCert(PublicKey publicKey, PrivateKey privateKey,
|
||||
String issuer, String subject) throws Exception {
|
||||
JcaX509v3CertificateBuilder builder = certBuilder(publicKey, issuer, subject);
|
||||
builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature));
|
||||
builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(false));
|
||||
builder.addExtension(Extension.keyUsage, true,
|
||||
new KeyUsage(KeyUsage.digitalSignature));
|
||||
builder.addExtension(Extension.basicConstraints, false,
|
||||
new BasicConstraints(false));
|
||||
|
||||
GeneralName[] names = new GeneralName[] { new GeneralName(GeneralName.dNSName, "localhost") };
|
||||
builder.addExtension(Extension.subjectAlternativeName, false, GeneralNames.getInstance(new DERSequence(names)));
|
||||
GeneralName[] names = new GeneralName[] {
|
||||
new GeneralName(GeneralName.dNSName, "localhost") };
|
||||
builder.addExtension(Extension.subjectAlternativeName, false,
|
||||
GeneralNames.getInstance(new DERSequence(names)));
|
||||
|
||||
return signCert(builder, privateKey);
|
||||
}
|
||||
|
||||
private JcaX509v3CertificateBuilder certBuilder(PublicKey publicKey, String issuer, String subject) {
|
||||
private JcaX509v3CertificateBuilder certBuilder(PublicKey publicKey, String issuer,
|
||||
String subject) {
|
||||
X500Name issuerName = new X500Name(String.format("dc=%s", issuer));
|
||||
X500Name subjectName = new X500Name(String.format("dc=%s", subject));
|
||||
|
||||
@@ -100,11 +110,14 @@ public class KeyTool {
|
||||
Date notBefore = new Date(now - ONE_DAY);
|
||||
Date notAfter = new Date(now + TEN_YEARS);
|
||||
|
||||
return new JcaX509v3CertificateBuilder(issuerName, serialNum, notBefore, notAfter, subjectName, publicKey);
|
||||
return new JcaX509v3CertificateBuilder(issuerName, serialNum, notBefore, notAfter,
|
||||
subjectName, publicKey);
|
||||
}
|
||||
|
||||
private X509Certificate signCert(JcaX509v3CertificateBuilder builder, PrivateKey privateKey) throws Exception {
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA").build(privateKey);
|
||||
private X509Certificate signCert(JcaX509v3CertificateBuilder builder,
|
||||
PrivateKey privateKey) throws Exception {
|
||||
ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSA")
|
||||
.build(privateKey);
|
||||
X509CertificateHolder holder = builder.build(signer);
|
||||
|
||||
return new JcaX509CertificateConverter().getCertificate(holder);
|
||||
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* Copyright 2018-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class RestTemplateEurekaClientTest extends BaseCertTest {
|
||||
|
||||
private static final Log log = LogFactory.getLog(RestTemplateEurekaClientTest.class);
|
||||
|
||||
private static EurekaServerRunner server;
|
||||
|
||||
private static EurekaClientRunner service;
|
||||
|
||||
@BeforeAll
|
||||
public static void setupAll() {
|
||||
server = startEurekaServer(RestTemplateEurekaClientTest.RestTemplateTestEurekaServer.class);
|
||||
service = startService(server, RestTemplateEurekaClientTest.RestTemplateTestApp.class);
|
||||
// Will use RestTemplate
|
||||
assertThat(service.discoveryClientOptionalArgs()).isInstanceOf(RestTemplateDiscoveryClientOptionalArgs.class);
|
||||
log.info("Successfully asserted that RestTemplate will be used");
|
||||
waitForRegistration(() -> new RestTemplateEurekaClientTest().createEurekaClient());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void tearDownAll() {
|
||||
stopService(service);
|
||||
stopEurekaServer(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
EurekaClientRunner createEurekaClient() {
|
||||
return new EurekaClientRunner(RestTemplateTestApp.class, server);
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
public static class RestTemplateTestApp {
|
||||
|
||||
// Want to force reusing exactly the same bean as on production without excluding
|
||||
// jersey from the classpath
|
||||
@Bean
|
||||
public RestTemplateDiscoveryClientOptionalArgs forceRestTemplateDiscoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties, DiscoveryClientOptionalArgsConfiguration configuration,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
|
||||
throws GeneralSecurityException, IOException {
|
||||
return configuration.restTemplateDiscoveryClientOptionalArgs(tlsProperties,
|
||||
eurekaClientHttpRequestFactorySupplier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SpringBootConfiguration
|
||||
@EnableAutoConfiguration
|
||||
@EnableEurekaServer
|
||||
public static class RestTemplateTestEurekaServer {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix</artifactId>
|
||||
<version>3.1.0-M3</version>
|
||||
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-netflix-eureka-client</artifactId>
|
||||
@@ -32,6 +32,15 @@
|
||||
<artifactId>spring-boot-starter-webflux</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-hystrix</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-ribbon</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-config-client</artifactId>
|
||||
@@ -51,38 +60,6 @@
|
||||
<groupId>com.netflix.eureka</groupId>
|
||||
<artifactId>eureka-client</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client4</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-core</artifactId>
|
||||
<version>${eureka-jersey.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey</groupId>
|
||||
<artifactId>jersey-client</artifactId>
|
||||
<version>${eureka-jersey.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client4</artifactId>
|
||||
<version>${eureka-jersey.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.inject</groupId>
|
||||
@@ -95,6 +72,46 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Eureka core deps that are now optional -->
|
||||
<dependency>
|
||||
<groupId>com.sun.jersey.contribs</groupId>
|
||||
<artifactId>jersey-apache-client4</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.archaius</groupId>
|
||||
<artifactId>archaius-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.netflix-commons</groupId>
|
||||
<artifactId>netflix-eventbus</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-loadbalancer</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-eureka</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.netflix.ribbon</groupId>
|
||||
<artifactId>ribbon-httpclient</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||
@@ -110,11 +127,6 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
|
||||
+13
-9
@@ -56,17 +56,19 @@ public class CloudEurekaClient extends DiscoveryClient {
|
||||
|
||||
private AtomicReference<EurekaHttpClient> eurekaHttpClient = new AtomicReference<>();
|
||||
|
||||
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config,
|
||||
ApplicationEventPublisher publisher) {
|
||||
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager,
|
||||
EurekaClientConfig config, ApplicationEventPublisher publisher) {
|
||||
this(applicationInfoManager, config, null, publisher);
|
||||
}
|
||||
|
||||
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager, EurekaClientConfig config,
|
||||
AbstractDiscoveryClientOptionalArgs<?> args, ApplicationEventPublisher publisher) {
|
||||
public CloudEurekaClient(ApplicationInfoManager applicationInfoManager,
|
||||
EurekaClientConfig config, AbstractDiscoveryClientOptionalArgs<?> args,
|
||||
ApplicationEventPublisher publisher) {
|
||||
super(applicationInfoManager, config, args);
|
||||
this.applicationInfoManager = applicationInfoManager;
|
||||
this.publisher = publisher;
|
||||
this.eurekaTransportField = ReflectionUtils.findField(DiscoveryClient.class, "eurekaTransport");
|
||||
this.eurekaTransportField = ReflectionUtils.findField(DiscoveryClient.class,
|
||||
"eurekaTransport");
|
||||
ReflectionUtils.makeAccessible(this.eurekaTransportField);
|
||||
}
|
||||
|
||||
@@ -79,7 +81,8 @@ public class CloudEurekaClient extends DiscoveryClient {
|
||||
}
|
||||
|
||||
public InstanceInfo getInstanceInfo(String appname, String instanceId) {
|
||||
EurekaHttpResponse<InstanceInfo> response = getEurekaHttpClient().getInstance(appname, instanceId);
|
||||
EurekaHttpResponse<InstanceInfo> response = getEurekaHttpClient()
|
||||
.getInstance(appname, instanceId);
|
||||
HttpStatus httpStatus = HttpStatus.valueOf(response.getStatusCode());
|
||||
if (httpStatus.is2xxSuccessful() && response.getEntity() != null) {
|
||||
return response.getEntity();
|
||||
@@ -91,8 +94,8 @@ public class CloudEurekaClient extends DiscoveryClient {
|
||||
if (this.eurekaHttpClient.get() == null) {
|
||||
try {
|
||||
Object eurekaTransport = this.eurekaTransportField.get(this);
|
||||
Field registrationClientField = ReflectionUtils.findField(eurekaTransport.getClass(),
|
||||
"registrationClient");
|
||||
Field registrationClientField = ReflectionUtils
|
||||
.findField(eurekaTransport.getClass(), "registrationClient");
|
||||
ReflectionUtils.makeAccessible(registrationClientField);
|
||||
this.eurekaHttpClient.compareAndSet(null,
|
||||
(EurekaHttpClient) registrationClientField.get(eurekaTransport));
|
||||
@@ -105,7 +108,8 @@ public class CloudEurekaClient extends DiscoveryClient {
|
||||
}
|
||||
|
||||
public void setStatus(InstanceStatus newStatus, InstanceInfo info) {
|
||||
getEurekaHttpClient().statusUpdate(info.getAppName(), info.getId(), newStatus, info);
|
||||
getEurekaHttpClient().statusUpdate(info.getAppName(), info.getId(), newStatus,
|
||||
info);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+33
-19
@@ -64,7 +64,8 @@ public class CloudEurekaTransportConfig implements EurekaTransportConfig {
|
||||
return sessionedClientReconnectIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setSessionedClientReconnectIntervalSeconds(int sessionedClientReconnectIntervalSeconds) {
|
||||
public void setSessionedClientReconnectIntervalSeconds(
|
||||
int sessionedClientReconnectIntervalSeconds) {
|
||||
this.sessionedClientReconnectIntervalSeconds = sessionedClientReconnectIntervalSeconds;
|
||||
}
|
||||
|
||||
@@ -72,7 +73,8 @@ public class CloudEurekaTransportConfig implements EurekaTransportConfig {
|
||||
return retryableClientQuarantineRefreshPercentage;
|
||||
}
|
||||
|
||||
public void setRetryableClientQuarantineRefreshPercentage(double retryableClientQuarantineRefreshPercentage) {
|
||||
public void setRetryableClientQuarantineRefreshPercentage(
|
||||
double retryableClientQuarantineRefreshPercentage) {
|
||||
this.retryableClientQuarantineRefreshPercentage = retryableClientQuarantineRefreshPercentage;
|
||||
}
|
||||
|
||||
@@ -80,7 +82,8 @@ public class CloudEurekaTransportConfig implements EurekaTransportConfig {
|
||||
return bootstrapResolverRefreshIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setBootstrapResolverRefreshIntervalSeconds(int bootstrapResolverRefreshIntervalSeconds) {
|
||||
public void setBootstrapResolverRefreshIntervalSeconds(
|
||||
int bootstrapResolverRefreshIntervalSeconds) {
|
||||
this.bootstrapResolverRefreshIntervalSeconds = bootstrapResolverRefreshIntervalSeconds;
|
||||
}
|
||||
|
||||
@@ -177,36 +180,47 @@ public class CloudEurekaTransportConfig implements EurekaTransportConfig {
|
||||
&& Objects.equals(readClusterVip, that.readClusterVip)
|
||||
&& Objects.equals(writeClusterVip, that.writeClusterVip)
|
||||
&& bootstrapResolverForQuery == that.bootstrapResolverForQuery
|
||||
&& Objects.equals(bootstrapResolverStrategy, that.bootstrapResolverStrategy)
|
||||
&& Objects.equals(bootstrapResolverStrategy,
|
||||
that.bootstrapResolverStrategy)
|
||||
&& applicationsResolverUseIp == that.applicationsResolverUseIp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(sessionedClientReconnectIntervalSeconds, retryableClientQuarantineRefreshPercentage,
|
||||
bootstrapResolverRefreshIntervalSeconds, applicationsResolverDataStalenessThresholdSeconds,
|
||||
asyncResolverRefreshIntervalMs, asyncResolverWarmUpTimeoutMs, asyncExecutorThreadPoolSize,
|
||||
readClusterVip, writeClusterVip, bootstrapResolverForQuery, bootstrapResolverStrategy,
|
||||
return Objects.hash(sessionedClientReconnectIntervalSeconds,
|
||||
retryableClientQuarantineRefreshPercentage,
|
||||
bootstrapResolverRefreshIntervalSeconds,
|
||||
applicationsResolverDataStalenessThresholdSeconds,
|
||||
asyncResolverRefreshIntervalMs, asyncResolverWarmUpTimeoutMs,
|
||||
asyncExecutorThreadPoolSize, readClusterVip, writeClusterVip,
|
||||
bootstrapResolverForQuery, bootstrapResolverStrategy,
|
||||
applicationsResolverUseIp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("CloudEurekaTransportConfig{").append("sessionedClientReconnectIntervalSeconds=")
|
||||
return new StringBuilder("CloudEurekaTransportConfig{")
|
||||
.append("sessionedClientReconnectIntervalSeconds=")
|
||||
.append(sessionedClientReconnectIntervalSeconds).append(", ")
|
||||
.append("retryableClientQuarantineRefreshPercentage=")
|
||||
.append(retryableClientQuarantineRefreshPercentage).append(", ")
|
||||
.append("bootstrapResolverRefreshIntervalSeconds=").append(bootstrapResolverRefreshIntervalSeconds)
|
||||
.append(", ").append("applicationsResolverDataStalenessThresholdSeconds=")
|
||||
.append("bootstrapResolverRefreshIntervalSeconds=")
|
||||
.append(bootstrapResolverRefreshIntervalSeconds).append(", ")
|
||||
.append("applicationsResolverDataStalenessThresholdSeconds=")
|
||||
.append(applicationsResolverDataStalenessThresholdSeconds).append(", ")
|
||||
.append("asyncResolverRefreshIntervalMs=").append(asyncResolverRefreshIntervalMs).append(", ")
|
||||
.append("asyncResolverWarmUpTimeoutMs=").append(asyncResolverWarmUpTimeoutMs).append(", ")
|
||||
.append("asyncExecutorThreadPoolSize=").append(asyncExecutorThreadPoolSize).append(", ")
|
||||
.append("readClusterVip='").append(readClusterVip).append("', ").append("writeClusterVip='")
|
||||
.append(writeClusterVip).append("', ").append("bootstrapResolverForQuery=")
|
||||
.append(bootstrapResolverForQuery).append(", ").append("bootstrapResolverStrategy='")
|
||||
.append(bootstrapResolverStrategy).append("', ").append("applicationsResolverUseIp=")
|
||||
.append(applicationsResolverUseIp).append(", ").append("}").toString();
|
||||
.append("asyncResolverRefreshIntervalMs=")
|
||||
.append(asyncResolverRefreshIntervalMs).append(", ")
|
||||
.append("asyncResolverWarmUpTimeoutMs=")
|
||||
.append(asyncResolverWarmUpTimeoutMs).append(", ")
|
||||
.append("asyncExecutorThreadPoolSize=")
|
||||
.append(asyncExecutorThreadPoolSize).append(", ")
|
||||
.append("readClusterVip='").append(readClusterVip).append("', ")
|
||||
.append("writeClusterVip='").append(writeClusterVip).append("', ")
|
||||
.append("bootstrapResolverForQuery=").append(bootstrapResolverForQuery)
|
||||
.append(", ").append("bootstrapResolverStrategy='")
|
||||
.append(bootstrapResolverStrategy).append("', ")
|
||||
.append("applicationsResolverUseIp=").append(applicationsResolverUseIp)
|
||||
.append(", ").append("}").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+74
-46
@@ -50,6 +50,7 @@ import org.springframework.cloud.autoconfigure.RefreshAutoConfiguration;
|
||||
import org.springframework.cloud.client.CommonsClientAutoConfiguration;
|
||||
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
|
||||
import org.springframework.cloud.client.actuator.HasFeatures;
|
||||
import org.springframework.cloud.client.discovery.noop.NoopDiscoveryClientAutoConfiguration;
|
||||
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
|
||||
import org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration;
|
||||
import org.springframework.cloud.commons.util.InetUtils;
|
||||
@@ -86,8 +87,10 @@ import static org.springframework.cloud.commons.util.IdUtils.getDefaultInstanceI
|
||||
@ConditionalOnClass(EurekaClientConfig.class)
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
|
||||
@ConditionalOnDiscoveryEnabled
|
||||
@AutoConfigureBefore({ CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
|
||||
@AutoConfigureAfter(name = { "org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration",
|
||||
@AutoConfigureBefore({ NoopDiscoveryClientAutoConfiguration.class,
|
||||
CommonsClientAutoConfiguration.class, ServiceRegistryAutoConfiguration.class })
|
||||
@AutoConfigureAfter(name = {
|
||||
"org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration",
|
||||
"org.springframework.cloud.autoconfigure.RefreshAutoConfiguration",
|
||||
"org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration",
|
||||
"org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration" })
|
||||
@@ -105,7 +108,8 @@ public class EurekaClientAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnMissingBean(value = EurekaClientConfig.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public EurekaClientConfigBean eurekaClientConfigBean(ConfigurableEnvironment env) {
|
||||
return new EurekaClientConfigBean();
|
||||
}
|
||||
@@ -121,25 +125,26 @@ public class EurekaClientAutoConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnMissingBean(value = EurekaInstanceConfig.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public EurekaInstanceConfigBean eurekaInstanceConfigBean(InetUtils inetUtils,
|
||||
ManagementMetadataProvider managementMetadataProvider) {
|
||||
String hostname = getProperty("eureka.instance.hostname");
|
||||
boolean preferIpAddress = Boolean.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
|
||||
boolean preferIpAddress = Boolean
|
||||
.parseBoolean(getProperty("eureka.instance.prefer-ip-address"));
|
||||
String ipAddress = getProperty("eureka.instance.ip-address");
|
||||
boolean isSecurePortEnabled = Boolean.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));
|
||||
boolean isSecurePortEnabled = Boolean
|
||||
.parseBoolean(getProperty("eureka.instance.secure-port-enabled"));
|
||||
|
||||
String serverContextPath = env.getProperty("server.servlet.context-path", "/");
|
||||
int serverPort = Integer.parseInt(env.getProperty("server.port", env.getProperty("port", "8080")));
|
||||
int serverPort = Integer.parseInt(
|
||||
env.getProperty("server.port", env.getProperty("port", "8080")));
|
||||
|
||||
Integer managementPort = env.getProperty("management.server.port", Integer.class);
|
||||
|
||||
String managementContextPath = env.getProperty("management.server.servlet.context-path");
|
||||
if (!StringUtils.hasText(managementContextPath)) {
|
||||
managementContextPath = env.getProperty("management.server.base-path");
|
||||
}
|
||||
|
||||
Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port", Integer.class);
|
||||
String managementContextPath = env
|
||||
.getProperty("management.server.servlet.context-path");
|
||||
Integer jmxPort = env.getProperty("com.sun.management.jmxremote.port",
|
||||
Integer.class);
|
||||
EurekaInstanceConfigBean instance = new EurekaInstanceConfigBean(inetUtils);
|
||||
|
||||
instance.setNonSecurePort(serverPort);
|
||||
@@ -167,8 +172,8 @@ public class EurekaClientAutoConfiguration {
|
||||
instance.setHealthCheckUrlPath(healthCheckUrlPath);
|
||||
}
|
||||
|
||||
ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort);
|
||||
ManagementMetadata metadata = managementMetadataProvider.get(instance, serverPort,
|
||||
serverContextPath, managementContextPath, managementPort);
|
||||
|
||||
if (metadata != null) {
|
||||
instance.setStatusPageUrl(metadata.getStatusPageUrl());
|
||||
@@ -177,15 +182,18 @@ public class EurekaClientAutoConfiguration {
|
||||
instance.setSecureHealthCheckUrl(metadata.getSecureHealthCheckUrl());
|
||||
}
|
||||
Map<String, String> metadataMap = instance.getMetadataMap();
|
||||
metadataMap.computeIfAbsent("management.port", k -> String.valueOf(metadata.getManagementPort()));
|
||||
metadataMap.computeIfAbsent("management.port",
|
||||
k -> String.valueOf(metadata.getManagementPort()));
|
||||
}
|
||||
else {
|
||||
// without the metadata the status and health check URLs will not be set
|
||||
// and the status page and health check url paths will not include the
|
||||
// context path so set them here
|
||||
if (StringUtils.hasText(managementContextPath)) {
|
||||
instance.setHealthCheckUrlPath(managementContextPath + instance.getHealthCheckUrlPath());
|
||||
instance.setStatusPageUrlPath(managementContextPath + instance.getStatusPageUrlPath());
|
||||
instance.setHealthCheckUrlPath(
|
||||
managementContextPath + instance.getHealthCheckUrlPath());
|
||||
instance.setStatusPageUrlPath(
|
||||
managementContextPath + instance.getStatusPageUrlPath());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +229,12 @@ public class EurekaClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(ApplicationContext context,
|
||||
EurekaServiceRegistry registry, EurekaRegistration registration) {
|
||||
@ConditionalOnProperty(
|
||||
value = "spring.cloud.service-registry.auto-registration.enabled",
|
||||
matchIfMissing = true)
|
||||
public EurekaAutoServiceRegistration eurekaAutoServiceRegistration(
|
||||
ApplicationContext context, EurekaServiceRegistry registry,
|
||||
EurekaRegistration registration) {
|
||||
return new EurekaAutoServiceRegistration(context, registry, registration);
|
||||
}
|
||||
|
||||
@@ -238,26 +249,34 @@ public class EurekaClientAutoConfiguration {
|
||||
private AbstractDiscoveryClientOptionalArgs<?> optionalArgs;
|
||||
|
||||
@Bean(destroyMethod = "shutdown")
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config) {
|
||||
return new CloudEurekaClient(manager, config, this.optionalArgs, this.context);
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager,
|
||||
EurekaClientConfig config) {
|
||||
return new CloudEurekaClient(manager, config, this.optionalArgs,
|
||||
this.context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
|
||||
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
|
||||
@ConditionalOnMissingBean(value = ApplicationInfoManager.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public ApplicationInfoManager eurekaApplicationInfoManager(
|
||||
EurekaInstanceConfig config) {
|
||||
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
|
||||
return new ApplicationInfoManager(config, instanceInfo);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||
@ConditionalOnProperty(
|
||||
value = "spring.cloud.service-registry.auto-registration.enabled",
|
||||
matchIfMissing = true)
|
||||
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
|
||||
CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager,
|
||||
@Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient)
|
||||
.with(healthCheckHandler).build();
|
||||
CloudEurekaInstanceConfig instanceConfig,
|
||||
ApplicationInfoManager applicationInfoManager, @Autowired(
|
||||
required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager)
|
||||
.with(eurekaClient).with(healthCheckHandler).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -273,11 +292,13 @@ public class EurekaClientAutoConfiguration {
|
||||
private AbstractDiscoveryClientOptionalArgs<?> optionalArgs;
|
||||
|
||||
@Bean(destroyMethod = "shutdown")
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
@org.springframework.cloud.context.config.annotation.RefreshScope
|
||||
@Lazy
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config,
|
||||
EurekaInstanceConfig instance, @Autowired(required = false) HealthCheckHandler healthCheckHandler) {
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager,
|
||||
EurekaClientConfig config, EurekaInstanceConfig instance,
|
||||
@Autowired(required = false) HealthCheckHandler healthCheckHandler) {
|
||||
// If we use the proxy of the ApplicationInfoManager we could run into a
|
||||
// problem
|
||||
// when shutdown is called on the CloudEurekaClient where the
|
||||
@@ -292,17 +313,19 @@ public class EurekaClientAutoConfiguration {
|
||||
else {
|
||||
appManager = manager;
|
||||
}
|
||||
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager, config, this.optionalArgs,
|
||||
this.context);
|
||||
CloudEurekaClient cloudEurekaClient = new CloudEurekaClient(appManager,
|
||||
config, this.optionalArgs, this.context);
|
||||
cloudEurekaClient.registerHealthCheck(healthCheckHandler);
|
||||
return cloudEurekaClient;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = ApplicationInfoManager.class, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnMissingBean(value = ApplicationInfoManager.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
@org.springframework.cloud.context.config.annotation.RefreshScope
|
||||
@Lazy
|
||||
public ApplicationInfoManager eurekaApplicationInfoManager(EurekaInstanceConfig config) {
|
||||
public ApplicationInfoManager eurekaApplicationInfoManager(
|
||||
EurekaInstanceConfig config) {
|
||||
InstanceInfo instanceInfo = new InstanceInfoFactory().create(config);
|
||||
return new ApplicationInfoManager(config, instanceInfo);
|
||||
}
|
||||
@@ -310,12 +333,15 @@ public class EurekaClientAutoConfiguration {
|
||||
@Bean
|
||||
@org.springframework.cloud.context.config.annotation.RefreshScope
|
||||
@ConditionalOnBean(AutoServiceRegistrationProperties.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled", matchIfMissing = true)
|
||||
@ConditionalOnProperty(
|
||||
value = "spring.cloud.service-registry.auto-registration.enabled",
|
||||
matchIfMissing = true)
|
||||
public EurekaRegistration eurekaRegistration(EurekaClient eurekaClient,
|
||||
CloudEurekaInstanceConfig instanceConfig, ApplicationInfoManager applicationInfoManager,
|
||||
@Autowired(required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager).with(eurekaClient)
|
||||
.with(healthCheckHandler).build();
|
||||
CloudEurekaInstanceConfig instanceConfig,
|
||||
ApplicationInfoManager applicationInfoManager, @Autowired(
|
||||
required = false) ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
return EurekaRegistration.builder(instanceConfig).with(applicationInfoManager)
|
||||
.with(eurekaClient).with(healthCheckHandler).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -333,7 +359,8 @@ public class EurekaClientAutoConfiguration {
|
||||
@Documented
|
||||
@ConditionalOnClass(RefreshScope.class)
|
||||
@ConditionalOnBean(RefreshAutoConfiguration.class)
|
||||
@ConditionalOnProperty(value = "eureka.client.refresh.enable", havingValue = "true", matchIfMissing = true)
|
||||
@ConditionalOnProperty(value = "eureka.client.refresh.enable", havingValue = "true",
|
||||
matchIfMissing = true)
|
||||
@interface ConditionalOnRefreshScope {
|
||||
|
||||
}
|
||||
@@ -354,7 +381,8 @@ public class EurekaClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "eureka.client.refresh.enable", havingValue = "false")
|
||||
@ConditionalOnProperty(value = "eureka.client.refresh.enable",
|
||||
havingValue = "false")
|
||||
static class OnPropertyDisabled {
|
||||
|
||||
}
|
||||
|
||||
+127
-76
@@ -52,7 +52,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
/**
|
||||
* Default Eureka URL.
|
||||
*/
|
||||
public static final String DEFAULT_URL = "http://localhost:8761" + DEFAULT_PREFIX + "/";
|
||||
public static final String DEFAULT_URL = "http://localhost:8761" + DEFAULT_PREFIX
|
||||
+ "/";
|
||||
|
||||
/**
|
||||
* Default availability zone if none is resolved based on region.
|
||||
@@ -473,7 +474,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
serviceUrls = this.serviceUrl.get(DEFAULT_ZONE);
|
||||
}
|
||||
if (!StringUtils.isEmpty(serviceUrls)) {
|
||||
final String[] serviceUrlsSplit = StringUtils.commaDelimitedListToStringArray(serviceUrls);
|
||||
final String[] serviceUrlsSplit = StringUtils
|
||||
.commaDelimitedListToStringArray(serviceUrls);
|
||||
List<String> eurekaServiceUrls = new ArrayList<>(serviceUrlsSplit.length);
|
||||
for (String eurekaServiceUrl : serviceUrlsSplit) {
|
||||
if (!endsWithSlash(eurekaServiceUrl)) {
|
||||
@@ -514,7 +516,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
@Override
|
||||
public String getExperimental(String name) {
|
||||
if (this.propertyResolver != null) {
|
||||
return this.propertyResolver.getProperty(PREFIX + ".experimental." + name, String.class, null);
|
||||
return this.propertyResolver.getProperty(PREFIX + ".experimental." + name,
|
||||
String.class, null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -562,7 +565,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return instanceInfoReplicationIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setInstanceInfoReplicationIntervalSeconds(int instanceInfoReplicationIntervalSeconds) {
|
||||
public void setInstanceInfoReplicationIntervalSeconds(
|
||||
int instanceInfoReplicationIntervalSeconds) {
|
||||
this.instanceInfoReplicationIntervalSeconds = instanceInfoReplicationIntervalSeconds;
|
||||
}
|
||||
|
||||
@@ -571,7 +575,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return initialInstanceInfoReplicationIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setInitialInstanceInfoReplicationIntervalSeconds(int initialInstanceInfoReplicationIntervalSeconds) {
|
||||
public void setInitialInstanceInfoReplicationIntervalSeconds(
|
||||
int initialInstanceInfoReplicationIntervalSeconds) {
|
||||
this.initialInstanceInfoReplicationIntervalSeconds = initialInstanceInfoReplicationIntervalSeconds;
|
||||
}
|
||||
|
||||
@@ -580,7 +585,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return eurekaServiceUrlPollIntervalSeconds;
|
||||
}
|
||||
|
||||
public void setEurekaServiceUrlPollIntervalSeconds(int eurekaServiceUrlPollIntervalSeconds) {
|
||||
public void setEurekaServiceUrlPollIntervalSeconds(
|
||||
int eurekaServiceUrlPollIntervalSeconds) {
|
||||
this.eurekaServiceUrlPollIntervalSeconds = eurekaServiceUrlPollIntervalSeconds;
|
||||
}
|
||||
|
||||
@@ -634,7 +640,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return eurekaServerConnectTimeoutSeconds;
|
||||
}
|
||||
|
||||
public void setEurekaServerConnectTimeoutSeconds(int eurekaServerConnectTimeoutSeconds) {
|
||||
public void setEurekaServerConnectTimeoutSeconds(
|
||||
int eurekaServerConnectTimeoutSeconds) {
|
||||
this.eurekaServerConnectTimeoutSeconds = eurekaServerConnectTimeoutSeconds;
|
||||
}
|
||||
|
||||
@@ -661,7 +668,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return eurekaServerTotalConnectionsPerHost;
|
||||
}
|
||||
|
||||
public void setEurekaServerTotalConnectionsPerHost(int eurekaServerTotalConnectionsPerHost) {
|
||||
public void setEurekaServerTotalConnectionsPerHost(
|
||||
int eurekaServerTotalConnectionsPerHost) {
|
||||
this.eurekaServerTotalConnectionsPerHost = eurekaServerTotalConnectionsPerHost;
|
||||
}
|
||||
|
||||
@@ -706,7 +714,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return eurekaConnectionIdleTimeoutSeconds;
|
||||
}
|
||||
|
||||
public void setEurekaConnectionIdleTimeoutSeconds(int eurekaConnectionIdleTimeoutSeconds) {
|
||||
public void setEurekaConnectionIdleTimeoutSeconds(
|
||||
int eurekaConnectionIdleTimeoutSeconds) {
|
||||
this.eurekaConnectionIdleTimeoutSeconds = eurekaConnectionIdleTimeoutSeconds;
|
||||
}
|
||||
|
||||
@@ -715,7 +724,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return registryRefreshSingleVipAddress;
|
||||
}
|
||||
|
||||
public void setRegistryRefreshSingleVipAddress(String registryRefreshSingleVipAddress) {
|
||||
public void setRegistryRefreshSingleVipAddress(
|
||||
String registryRefreshSingleVipAddress) {
|
||||
this.registryRefreshSingleVipAddress = registryRefreshSingleVipAddress;
|
||||
}
|
||||
|
||||
@@ -733,7 +743,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return heartbeatExecutorExponentialBackOffBound;
|
||||
}
|
||||
|
||||
public void setHeartbeatExecutorExponentialBackOffBound(int heartbeatExecutorExponentialBackOffBound) {
|
||||
public void setHeartbeatExecutorExponentialBackOffBound(
|
||||
int heartbeatExecutorExponentialBackOffBound) {
|
||||
this.heartbeatExecutorExponentialBackOffBound = heartbeatExecutorExponentialBackOffBound;
|
||||
}
|
||||
|
||||
@@ -742,7 +753,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return cacheRefreshExecutorThreadPoolSize;
|
||||
}
|
||||
|
||||
public void setCacheRefreshExecutorThreadPoolSize(int cacheRefreshExecutorThreadPoolSize) {
|
||||
public void setCacheRefreshExecutorThreadPoolSize(
|
||||
int cacheRefreshExecutorThreadPoolSize) {
|
||||
this.cacheRefreshExecutorThreadPoolSize = cacheRefreshExecutorThreadPoolSize;
|
||||
}
|
||||
|
||||
@@ -751,7 +763,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return cacheRefreshExecutorExponentialBackOffBound;
|
||||
}
|
||||
|
||||
public void setCacheRefreshExecutorExponentialBackOffBound(int cacheRefreshExecutorExponentialBackOffBound) {
|
||||
public void setCacheRefreshExecutorExponentialBackOffBound(
|
||||
int cacheRefreshExecutorExponentialBackOffBound) {
|
||||
this.cacheRefreshExecutorExponentialBackOffBound = cacheRefreshExecutorExponentialBackOffBound;
|
||||
}
|
||||
|
||||
@@ -916,7 +929,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return shouldEnforceRegistrationAtInit;
|
||||
}
|
||||
|
||||
public void setShouldEnforceRegistrationAtInit(boolean shouldEnforceRegistrationAtInit) {
|
||||
public void setShouldEnforceRegistrationAtInit(
|
||||
boolean shouldEnforceRegistrationAtInit) {
|
||||
this.shouldEnforceRegistrationAtInit = shouldEnforceRegistrationAtInit;
|
||||
}
|
||||
|
||||
@@ -938,8 +952,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
return false;
|
||||
}
|
||||
EurekaClientConfigBean that = (EurekaClientConfigBean) o;
|
||||
return Objects.equals(propertyResolver, that.propertyResolver) && enabled == that.enabled
|
||||
&& Objects.equals(transport, that.transport)
|
||||
return Objects.equals(propertyResolver, that.propertyResolver)
|
||||
&& enabled == that.enabled && Objects.equals(transport, that.transport)
|
||||
&& registryFetchIntervalSeconds == that.registryFetchIntervalSeconds
|
||||
&& instanceInfoReplicationIntervalSeconds == that.instanceInfoReplicationIntervalSeconds
|
||||
&& initialInstanceInfoReplicationIntervalSeconds == that.initialInstanceInfoReplicationIntervalSeconds
|
||||
@@ -953,91 +967,128 @@ public class EurekaClientConfigBean implements EurekaClientConfig, Ordered {
|
||||
&& heartbeatExecutorExponentialBackOffBound == that.heartbeatExecutorExponentialBackOffBound
|
||||
&& cacheRefreshExecutorThreadPoolSize == that.cacheRefreshExecutorThreadPoolSize
|
||||
&& cacheRefreshExecutorExponentialBackOffBound == that.cacheRefreshExecutorExponentialBackOffBound
|
||||
&& gZipContent == that.gZipContent && useDnsForFetchingServiceUrls == that.useDnsForFetchingServiceUrls
|
||||
&& registerWithEureka == that.registerWithEureka && preferSameZoneEureka == that.preferSameZoneEureka
|
||||
&& gZipContent == that.gZipContent
|
||||
&& useDnsForFetchingServiceUrls == that.useDnsForFetchingServiceUrls
|
||||
&& registerWithEureka == that.registerWithEureka
|
||||
&& preferSameZoneEureka == that.preferSameZoneEureka
|
||||
&& logDeltaDiff == that.logDeltaDiff && disableDelta == that.disableDelta
|
||||
&& filterOnlyUpInstances == that.filterOnlyUpInstances && fetchRegistry == that.fetchRegistry
|
||||
&& filterOnlyUpInstances == that.filterOnlyUpInstances
|
||||
&& fetchRegistry == that.fetchRegistry
|
||||
&& allowRedirects == that.allowRedirects
|
||||
&& onDemandUpdateStatusChange == that.onDemandUpdateStatusChange
|
||||
&& shouldUnregisterOnShutdown == that.shouldUnregisterOnShutdown
|
||||
&& shouldEnforceRegistrationAtInit == that.shouldEnforceRegistrationAtInit
|
||||
&& Objects.equals(proxyPort, that.proxyPort) && Objects.equals(proxyHost, that.proxyHost)
|
||||
&& Objects.equals(proxyPort, that.proxyPort)
|
||||
&& Objects.equals(proxyHost, that.proxyHost)
|
||||
&& Objects.equals(proxyUserName, that.proxyUserName)
|
||||
&& Objects.equals(proxyPassword, that.proxyPassword)
|
||||
&& Objects.equals(backupRegistryImpl, that.backupRegistryImpl)
|
||||
&& Objects.equals(eurekaServerURLContext, that.eurekaServerURLContext)
|
||||
&& Objects.equals(eurekaServerPort, that.eurekaServerPort)
|
||||
&& Objects.equals(eurekaServerDNSName, that.eurekaServerDNSName) && Objects.equals(region, that.region)
|
||||
&& Objects.equals(registryRefreshSingleVipAddress, that.registryRefreshSingleVipAddress)
|
||||
&& Objects.equals(eurekaServerDNSName, that.eurekaServerDNSName)
|
||||
&& Objects.equals(region, that.region)
|
||||
&& Objects.equals(registryRefreshSingleVipAddress,
|
||||
that.registryRefreshSingleVipAddress)
|
||||
&& Objects.equals(serviceUrl, that.serviceUrl)
|
||||
&& Objects.equals(fetchRemoteRegionsRegistry, that.fetchRemoteRegionsRegistry)
|
||||
&& Objects.equals(fetchRemoteRegionsRegistry,
|
||||
that.fetchRemoteRegionsRegistry)
|
||||
&& Objects.equals(availabilityZones, that.availabilityZones)
|
||||
&& Objects.equals(dollarReplacement, that.dollarReplacement)
|
||||
&& Objects.equals(escapeCharReplacement, that.escapeCharReplacement)
|
||||
&& Objects.equals(encoderName, that.encoderName) && Objects.equals(decoderName, that.decoderName)
|
||||
&& Objects.equals(clientDataAccept, that.clientDataAccept) && Objects.equals(order, that.order);
|
||||
&& Objects.equals(encoderName, that.encoderName)
|
||||
&& Objects.equals(decoderName, that.decoderName)
|
||||
&& Objects.equals(clientDataAccept, that.clientDataAccept)
|
||||
&& Objects.equals(order, that.order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(propertyResolver, enabled, transport, registryFetchIntervalSeconds,
|
||||
instanceInfoReplicationIntervalSeconds, initialInstanceInfoReplicationIntervalSeconds,
|
||||
eurekaServiceUrlPollIntervalSeconds, proxyPort, proxyHost, proxyUserName, proxyPassword,
|
||||
eurekaServerReadTimeoutSeconds, eurekaServerConnectTimeoutSeconds, backupRegistryImpl,
|
||||
eurekaServerTotalConnections, eurekaServerTotalConnectionsPerHost, eurekaServerURLContext,
|
||||
eurekaServerPort, eurekaServerDNSName, region, eurekaConnectionIdleTimeoutSeconds,
|
||||
registryRefreshSingleVipAddress, heartbeatExecutorThreadPoolSize,
|
||||
heartbeatExecutorExponentialBackOffBound, cacheRefreshExecutorThreadPoolSize,
|
||||
cacheRefreshExecutorExponentialBackOffBound, serviceUrl, gZipContent, useDnsForFetchingServiceUrls,
|
||||
registerWithEureka, preferSameZoneEureka, logDeltaDiff, disableDelta, fetchRemoteRegionsRegistry,
|
||||
availabilityZones, filterOnlyUpInstances, fetchRegistry, dollarReplacement, escapeCharReplacement,
|
||||
allowRedirects, onDemandUpdateStatusChange, encoderName, decoderName, clientDataAccept,
|
||||
shouldUnregisterOnShutdown, shouldEnforceRegistrationAtInit, order);
|
||||
return Objects.hash(propertyResolver, enabled, transport,
|
||||
registryFetchIntervalSeconds, instanceInfoReplicationIntervalSeconds,
|
||||
initialInstanceInfoReplicationIntervalSeconds,
|
||||
eurekaServiceUrlPollIntervalSeconds, proxyPort, proxyHost, proxyUserName,
|
||||
proxyPassword, eurekaServerReadTimeoutSeconds,
|
||||
eurekaServerConnectTimeoutSeconds, backupRegistryImpl,
|
||||
eurekaServerTotalConnections, eurekaServerTotalConnectionsPerHost,
|
||||
eurekaServerURLContext, eurekaServerPort, eurekaServerDNSName, region,
|
||||
eurekaConnectionIdleTimeoutSeconds, registryRefreshSingleVipAddress,
|
||||
heartbeatExecutorThreadPoolSize, heartbeatExecutorExponentialBackOffBound,
|
||||
cacheRefreshExecutorThreadPoolSize,
|
||||
cacheRefreshExecutorExponentialBackOffBound, serviceUrl, gZipContent,
|
||||
useDnsForFetchingServiceUrls, registerWithEureka, preferSameZoneEureka,
|
||||
logDeltaDiff, disableDelta, fetchRemoteRegionsRegistry, availabilityZones,
|
||||
filterOnlyUpInstances, fetchRegistry, dollarReplacement,
|
||||
escapeCharReplacement, allowRedirects, onDemandUpdateStatusChange,
|
||||
encoderName, decoderName, clientDataAccept, shouldUnregisterOnShutdown,
|
||||
shouldEnforceRegistrationAtInit, order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("EurekaClientConfigBean{").append("propertyResolver=").append(propertyResolver)
|
||||
.append(", ").append("enabled=").append(enabled).append(", ").append("transport=").append(transport)
|
||||
.append(", ").append("registryFetchIntervalSeconds=").append(registryFetchIntervalSeconds).append(", ")
|
||||
.append("instanceInfoReplicationIntervalSeconds=").append(instanceInfoReplicationIntervalSeconds)
|
||||
.append(", ").append("initialInstanceInfoReplicationIntervalSeconds=")
|
||||
return new StringBuilder("EurekaClientConfigBean{").append("propertyResolver=")
|
||||
.append(propertyResolver).append(", ").append("enabled=").append(enabled)
|
||||
.append(", ").append("transport=").append(transport).append(", ")
|
||||
.append("registryFetchIntervalSeconds=")
|
||||
.append(registryFetchIntervalSeconds).append(", ")
|
||||
.append("instanceInfoReplicationIntervalSeconds=")
|
||||
.append(instanceInfoReplicationIntervalSeconds).append(", ")
|
||||
.append("initialInstanceInfoReplicationIntervalSeconds=")
|
||||
.append(initialInstanceInfoReplicationIntervalSeconds).append(", ")
|
||||
.append("eurekaServiceUrlPollIntervalSeconds=").append(eurekaServiceUrlPollIntervalSeconds).append(", ")
|
||||
.append("proxyPort='").append(proxyPort).append("', ").append("proxyHost='").append(proxyHost)
|
||||
.append("', ").append("proxyUserName='").append(proxyUserName).append("', ").append("proxyPassword='")
|
||||
.append(proxyPassword).append("', ").append("eurekaServerReadTimeoutSeconds=")
|
||||
.append(eurekaServerReadTimeoutSeconds).append(", ").append("eurekaServerConnectTimeoutSeconds=")
|
||||
.append(eurekaServerConnectTimeoutSeconds).append(", ").append("backupRegistryImpl='")
|
||||
.append(backupRegistryImpl).append("', ").append("eurekaServerTotalConnections=")
|
||||
.append(eurekaServerTotalConnections).append(", ").append("eurekaServerTotalConnectionsPerHost=")
|
||||
.append(eurekaServerTotalConnectionsPerHost).append(", ").append("eurekaServerURLContext='")
|
||||
.append(eurekaServerURLContext).append("', ").append("eurekaServerPort='").append(eurekaServerPort)
|
||||
.append("', ").append("eurekaServerDNSName='").append(eurekaServerDNSName).append("', ")
|
||||
.append("region='").append(region).append("', ").append("eurekaConnectionIdleTimeoutSeconds=")
|
||||
.append(eurekaConnectionIdleTimeoutSeconds).append(", ").append("registryRefreshSingleVipAddress='")
|
||||
.append(registryRefreshSingleVipAddress).append("', ").append("heartbeatExecutorThreadPoolSize=")
|
||||
.append("eurekaServiceUrlPollIntervalSeconds=")
|
||||
.append(eurekaServiceUrlPollIntervalSeconds).append(", ")
|
||||
.append("proxyPort='").append(proxyPort).append("', ")
|
||||
.append("proxyHost='").append(proxyHost).append("', ")
|
||||
.append("proxyUserName='").append(proxyUserName).append("', ")
|
||||
.append("proxyPassword='").append(proxyPassword).append("', ")
|
||||
.append("eurekaServerReadTimeoutSeconds=")
|
||||
.append(eurekaServerReadTimeoutSeconds).append(", ")
|
||||
.append("eurekaServerConnectTimeoutSeconds=")
|
||||
.append(eurekaServerConnectTimeoutSeconds).append(", ")
|
||||
.append("backupRegistryImpl='").append(backupRegistryImpl).append("', ")
|
||||
.append("eurekaServerTotalConnections=")
|
||||
.append(eurekaServerTotalConnections).append(", ")
|
||||
.append("eurekaServerTotalConnectionsPerHost=")
|
||||
.append(eurekaServerTotalConnectionsPerHost).append(", ")
|
||||
.append("eurekaServerURLContext='").append(eurekaServerURLContext)
|
||||
.append("', ").append("eurekaServerPort='").append(eurekaServerPort)
|
||||
.append("', ").append("eurekaServerDNSName='").append(eurekaServerDNSName)
|
||||
.append("', ").append("region='").append(region).append("', ")
|
||||
.append("eurekaConnectionIdleTimeoutSeconds=")
|
||||
.append(eurekaConnectionIdleTimeoutSeconds).append(", ")
|
||||
.append("registryRefreshSingleVipAddress='")
|
||||
.append(registryRefreshSingleVipAddress).append("', ")
|
||||
.append("heartbeatExecutorThreadPoolSize=")
|
||||
.append(heartbeatExecutorThreadPoolSize).append(", ")
|
||||
.append("heartbeatExecutorExponentialBackOffBound=").append(heartbeatExecutorExponentialBackOffBound)
|
||||
.append(", ").append("cacheRefreshExecutorThreadPoolSize=").append(cacheRefreshExecutorThreadPoolSize)
|
||||
.append(", ").append("cacheRefreshExecutorExponentialBackOffBound=")
|
||||
.append(cacheRefreshExecutorExponentialBackOffBound).append(", ").append("serviceUrl=")
|
||||
.append(serviceUrl).append(", ").append("gZipContent=").append(gZipContent).append(", ")
|
||||
.append("useDnsForFetchingServiceUrls=").append(useDnsForFetchingServiceUrls).append(", ")
|
||||
.append("registerWithEureka=").append(registerWithEureka).append(", ").append("preferSameZoneEureka=")
|
||||
.append(preferSameZoneEureka).append(", ").append("logDeltaDiff=").append(logDeltaDiff).append(", ")
|
||||
.append("disableDelta=").append(disableDelta).append(", ").append("fetchRemoteRegionsRegistry='")
|
||||
.append(fetchRemoteRegionsRegistry).append("', ").append("availabilityZones=").append(availabilityZones)
|
||||
.append(", ").append("filterOnlyUpInstances=").append(filterOnlyUpInstances).append(", ")
|
||||
.append("fetchRegistry=").append(fetchRegistry).append(", ").append("dollarReplacement='")
|
||||
.append(dollarReplacement).append("', ").append("escapeCharReplacement='").append(escapeCharReplacement)
|
||||
.append("', ").append("allowRedirects=").append(allowRedirects).append(", ")
|
||||
.append("onDemandUpdateStatusChange=").append(onDemandUpdateStatusChange).append(", ")
|
||||
.append("encoderName='").append(encoderName).append("', ").append("decoderName='").append(decoderName)
|
||||
.append("', ").append("clientDataAccept='").append(clientDataAccept).append("', ")
|
||||
.append("heartbeatExecutorExponentialBackOffBound=")
|
||||
.append(heartbeatExecutorExponentialBackOffBound).append(", ")
|
||||
.append("cacheRefreshExecutorThreadPoolSize=")
|
||||
.append(cacheRefreshExecutorThreadPoolSize).append(", ")
|
||||
.append("cacheRefreshExecutorExponentialBackOffBound=")
|
||||
.append(cacheRefreshExecutorExponentialBackOffBound).append(", ")
|
||||
.append("serviceUrl=").append(serviceUrl).append(", ")
|
||||
.append("gZipContent=").append(gZipContent).append(", ")
|
||||
.append("useDnsForFetchingServiceUrls=")
|
||||
.append(useDnsForFetchingServiceUrls).append(", ")
|
||||
.append("registerWithEureka=").append(registerWithEureka).append(", ")
|
||||
.append("preferSameZoneEureka=").append(preferSameZoneEureka).append(", ")
|
||||
.append("logDeltaDiff=").append(logDeltaDiff).append(", ")
|
||||
.append("disableDelta=").append(disableDelta).append(", ")
|
||||
.append("fetchRemoteRegionsRegistry='").append(fetchRemoteRegionsRegistry)
|
||||
.append("', ").append("availabilityZones=").append(availabilityZones)
|
||||
.append(", ").append("filterOnlyUpInstances=")
|
||||
.append(filterOnlyUpInstances).append(", ").append("fetchRegistry=")
|
||||
.append(fetchRegistry).append(", ").append("dollarReplacement='")
|
||||
.append(dollarReplacement).append("', ").append("escapeCharReplacement='")
|
||||
.append(escapeCharReplacement).append("', ").append("allowRedirects=")
|
||||
.append(allowRedirects).append(", ").append("onDemandUpdateStatusChange=")
|
||||
.append(onDemandUpdateStatusChange).append(", ").append("encoderName='")
|
||||
.append(encoderName).append("', ").append("decoderName='")
|
||||
.append(decoderName).append("', ").append("clientDataAccept='")
|
||||
.append(clientDataAccept).append("', ")
|
||||
.append("shouldUnregisterOnShutdown='").append(shouldUnregisterOnShutdown)
|
||||
.append("shouldEnforceRegistrationAtInit='").append(shouldEnforceRegistrationAtInit).append("', ")
|
||||
.append("order='").append(order).append("'}").toString();
|
||||
.append("shouldEnforceRegistrationAtInit='")
|
||||
.append(shouldEnforceRegistrationAtInit).append("', ").append("order='")
|
||||
.append(order).append("'}").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+30
-3
@@ -20,6 +20,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.EurekaInstanceConfig;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
@@ -47,7 +48,13 @@ public class EurekaDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
private final EurekaClientConfig clientConfig;
|
||||
|
||||
public EurekaDiscoveryClient(EurekaClient eurekaClient, EurekaClientConfig clientConfig) {
|
||||
@Deprecated
|
||||
public EurekaDiscoveryClient(EurekaInstanceConfig config, EurekaClient eurekaClient) {
|
||||
this(eurekaClient, eurekaClient.getEurekaClientConfig());
|
||||
}
|
||||
|
||||
public EurekaDiscoveryClient(EurekaClient eurekaClient,
|
||||
EurekaClientConfig clientConfig) {
|
||||
this.clientConfig = clientConfig;
|
||||
this.eurekaClient = eurekaClient;
|
||||
}
|
||||
@@ -59,7 +66,8 @@ public class EurekaDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId, false);
|
||||
List<InstanceInfo> infos = this.eurekaClient.getInstancesByVipAddress(serviceId,
|
||||
false);
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
for (InstanceInfo info : infos) {
|
||||
instances.add(new EurekaServiceInstance(info));
|
||||
@@ -87,7 +95,26 @@ public class EurekaDiscoveryClient implements DiscoveryClient {
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return clientConfig instanceof Ordered ? ((Ordered) clientConfig).getOrder() : DiscoveryClient.DEFAULT_ORDER;
|
||||
return clientConfig instanceof Ordered ? ((Ordered) clientConfig).getOrder()
|
||||
: DiscoveryClient.DEFAULT_ORDER;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Eureka-specific {@link ServiceInstance} implementation. Extends
|
||||
* {@link org.springframework.cloud.netflix.eureka.EurekaServiceInstance} for
|
||||
* backwards compatibility.
|
||||
*
|
||||
* @deprecated In favor of
|
||||
* {@link org.springframework.cloud.netflix.eureka.EurekaServiceInstance}.
|
||||
*/
|
||||
@Deprecated
|
||||
public static class EurekaServiceInstance
|
||||
extends org.springframework.cloud.netflix.eureka.EurekaServiceInstance {
|
||||
|
||||
public EurekaServiceInstance(InstanceInfo instance) {
|
||||
super(instance);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-2
@@ -51,14 +51,27 @@ import org.springframework.context.annotation.Configuration;
|
||||
@ConditionalOnBlockingDiscoveryEnabled
|
||||
public class EurekaDiscoveryClientConfiguration {
|
||||
|
||||
/**
|
||||
* Deprecated in favor of auto configuration order.
|
||||
* @return Marker bean
|
||||
* @deprecated in favor of auto configuration order.
|
||||
*/
|
||||
@Deprecated
|
||||
@Bean
|
||||
public Marker eurekaDiscoverClientMarker() {
|
||||
return new Marker();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EurekaDiscoveryClient discoveryClient(EurekaClient client, EurekaClientConfig clientConfig) {
|
||||
public EurekaDiscoveryClient discoveryClient(EurekaClient client,
|
||||
EurekaClientConfig clientConfig) {
|
||||
return new EurekaDiscoveryClient(client, clientConfig);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnProperty(value = "eureka.client.healthcheck.enabled", matchIfMissing = false)
|
||||
@ConditionalOnProperty(value = "eureka.client.healthcheck.enabled",
|
||||
matchIfMissing = false)
|
||||
protected static class EurekaHealthCheckHandlerConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
@@ -72,6 +85,16 @@ public class EurekaDiscoveryClientConfiguration {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Deprecated in favor of auto configuration order.
|
||||
*
|
||||
* @deprecated in favor of auto configuration order.
|
||||
*/
|
||||
@Deprecated
|
||||
class Marker {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RefreshScopeRefreshedEvent.class)
|
||||
protected static class EurekaClientConfigurationRefresher
|
||||
|
||||
+103
-19
@@ -30,12 +30,17 @@ import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.boot.actuate.health.CompositeHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.DefaultHealthIndicatorRegistry;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthAggregator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.HealthIndicatorRegistryFactory;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Status;
|
||||
import org.springframework.boot.actuate.health.StatusAggregator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthContributor;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.Lifecycle;
|
||||
@@ -48,7 +53,7 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
* On each heartbeat Eureka performs the health check invoking registered
|
||||
* {@link HealthCheckHandler}. By default this implementation will perform aggregation of
|
||||
* all registered {@link HealthIndicator} through registered {@link StatusAggregator}.
|
||||
* all registered {@link HealthIndicator} through registered {@link HealthAggregator}.
|
||||
*
|
||||
* A {@code null} status is returned when the application context is closed (or in the
|
||||
* process of being closed). This prevents Eureka from updating the health status and only
|
||||
@@ -60,9 +65,10 @@ import org.springframework.util.Assert;
|
||||
* @author Bertrand Renuart
|
||||
* @see HealthCheckHandler
|
||||
* @see StatusAggregator
|
||||
* @see HealthAggregator
|
||||
*/
|
||||
public class EurekaHealthCheckHandler
|
||||
implements HealthCheckHandler, ApplicationContextAware, InitializingBean, Ordered, Lifecycle {
|
||||
public class EurekaHealthCheckHandler implements HealthCheckHandler,
|
||||
ApplicationContextAware, InitializingBean, Ordered, Lifecycle {
|
||||
|
||||
private static final Map<Status, InstanceInfo.InstanceStatus> STATUS_MAPPING = new HashMap<Status, InstanceInfo.InstanceStatus>() {
|
||||
{
|
||||
@@ -77,15 +83,33 @@ public class EurekaHealthCheckHandler
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Map<String, HealthIndicator> healthIndicators = new HashMap<>();
|
||||
|
||||
/**
|
||||
* {@code true} until the context is stopped.
|
||||
*/
|
||||
private boolean running = true;
|
||||
|
||||
private Map<String, HealthIndicator> healthIndicators;
|
||||
|
||||
private Map<String, ReactiveHealthIndicator> reactiveHealthIndicators = new HashMap<>();
|
||||
|
||||
@Deprecated
|
||||
private CompositeHealthIndicator healthIndicator;
|
||||
|
||||
@Deprecated
|
||||
private HealthIndicatorRegistryFactory healthIndicatorRegistryFactory;
|
||||
|
||||
@Deprecated
|
||||
private HealthAggregator healthAggregator;
|
||||
|
||||
@Deprecated
|
||||
public EurekaHealthCheckHandler(HealthAggregator healthAggregator) {
|
||||
Assert.notNull(healthAggregator, "HealthAggregator must not be null");
|
||||
this.healthAggregator = healthAggregator;
|
||||
healthIndicatorRegistryFactory = new HealthIndicatorRegistryFactory();
|
||||
healthIndicator = new CompositeHealthIndicator(this.healthAggregator,
|
||||
new DefaultHealthIndicatorRegistry());
|
||||
}
|
||||
|
||||
public EurekaHealthCheckHandler(StatusAggregator statusAggregator) {
|
||||
this.statusAggregator = statusAggregator;
|
||||
Assert.notNull(statusAggregator, "StatusAggregator must not be null");
|
||||
@@ -93,18 +117,53 @@ public class EurekaHealthCheckHandler
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
final Map<String, HealthIndicator> healthIndicators = applicationContext.getBeansOfType(HealthIndicator.class);
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
final Map<String, HealthIndicator> healthIndicators = applicationContext
|
||||
.getBeansOfType(HealthIndicator.class);
|
||||
this.healthIndicators = new HashMap<>();
|
||||
|
||||
final Map<String, ReactiveHealthIndicator> reactiveHealthIndicators = applicationContext
|
||||
.getBeansOfType(ReactiveHealthIndicator.class);
|
||||
|
||||
populateHealthIndicators(healthIndicators);
|
||||
populateReactiveHealthIndicators(reactiveHealthIndicators);
|
||||
if (statusAggregator != null) {
|
||||
populateHealthIndicators(healthIndicators);
|
||||
populateReactiveHealthIndicators(reactiveHealthIndicators);
|
||||
}
|
||||
else {
|
||||
createHealthIndicator(healthIndicators);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void createHealthIndicator(Map<String, HealthIndicator> healthIndicators) {
|
||||
for (Map.Entry<String, HealthIndicator> entry : healthIndicators.entrySet()) {
|
||||
|
||||
// ignore EurekaHealthIndicator and flatten the rest of the composite
|
||||
// otherwise there is a never ending cycle of down. See gh-643
|
||||
if (entry.getValue() instanceof DiscoveryCompositeHealthIndicator) {
|
||||
DiscoveryCompositeHealthIndicator indicator = (DiscoveryCompositeHealthIndicator) entry
|
||||
.getValue();
|
||||
for (DiscoveryCompositeHealthIndicator.Holder holder : indicator
|
||||
.getHealthIndicators()) {
|
||||
if (!(holder.getDelegate() instanceof EurekaHealthIndicator)) {
|
||||
this.healthIndicators.put(holder.getDelegate().getName(), holder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
this.healthIndicators.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
healthIndicator = new CompositeHealthIndicator(healthAggregator,
|
||||
healthIndicatorRegistryFactory
|
||||
.createHealthIndicatorRegistry(this.healthIndicators));
|
||||
}
|
||||
|
||||
void populateHealthIndicators(Map<String, HealthIndicator> healthIndicators) {
|
||||
@@ -112,9 +171,11 @@ public class EurekaHealthCheckHandler
|
||||
// ignore EurekaHealthIndicator and flatten the rest of the composite
|
||||
// otherwise there is a never ending cycle of down. See gh-643
|
||||
if (entry.getValue() instanceof DiscoveryCompositeHealthContributor) {
|
||||
DiscoveryCompositeHealthContributor indicator = (DiscoveryCompositeHealthContributor) entry.getValue();
|
||||
DiscoveryCompositeHealthContributor indicator = (DiscoveryCompositeHealthContributor) entry
|
||||
.getValue();
|
||||
indicator.forEach(contributor -> {
|
||||
if (!(contributor.getContributor() instanceof EurekaHealthIndicator)) {
|
||||
if (!(contributor
|
||||
.getContributor() instanceof EurekaHealthIndicator)) {
|
||||
this.healthIndicators.put(contributor.getName(),
|
||||
(HealthIndicator) contributor.getContributor());
|
||||
}
|
||||
@@ -126,8 +187,10 @@ public class EurekaHealthCheckHandler
|
||||
}
|
||||
}
|
||||
|
||||
void populateReactiveHealthIndicators(Map<String, ReactiveHealthIndicator> reactiveHealthIndicators) {
|
||||
for (Map.Entry<String, ReactiveHealthIndicator> entry : reactiveHealthIndicators.entrySet()) {
|
||||
void populateReactiveHealthIndicators(
|
||||
Map<String, ReactiveHealthIndicator> reactiveHealthIndicators) {
|
||||
for (Map.Entry<String, ReactiveHealthIndicator> entry : reactiveHealthIndicators
|
||||
.entrySet()) {
|
||||
this.reactiveHealthIndicators.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
@@ -146,22 +209,38 @@ public class EurekaHealthCheckHandler
|
||||
}
|
||||
|
||||
protected InstanceStatus getHealthStatus() {
|
||||
Status status = getStatus(statusAggregator);
|
||||
final Status status;
|
||||
if (statusAggregator != null) {
|
||||
status = getStatus(statusAggregator);
|
||||
}
|
||||
else {
|
||||
status = getStatus(getHealthIndicator());
|
||||
}
|
||||
return mapToInstanceStatus(status);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
private Status getStatus(CompositeHealthIndicator healthIndicator) {
|
||||
Status status;
|
||||
status = healthIndicator.health().getStatus();
|
||||
return status;
|
||||
}
|
||||
|
||||
protected Status getStatus(StatusAggregator statusAggregator) {
|
||||
Status status;
|
||||
|
||||
Set<Status> statusSet = new HashSet<>();
|
||||
if (healthIndicators != null) {
|
||||
statusSet.addAll(healthIndicators.values().stream().map(HealthIndicator::health).map(Health::getStatus)
|
||||
.collect(Collectors.toSet()));
|
||||
statusSet.addAll(
|
||||
healthIndicators.values().stream().map(HealthIndicator::health)
|
||||
.map(Health::getStatus).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
if (reactiveHealthIndicators != null) {
|
||||
statusSet.addAll(reactiveHealthIndicators.values().stream().map(ReactiveHealthIndicator::health)
|
||||
.map(Mono::block).filter(Objects::nonNull).map(Health::getStatus).collect(Collectors.toSet()));
|
||||
statusSet.addAll(reactiveHealthIndicators.values().stream()
|
||||
.map(ReactiveHealthIndicator::health).map(Mono::block)
|
||||
.filter(Objects::nonNull).map(Health::getStatus)
|
||||
.collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
status = statusAggregator.getAggregateStatus(statusSet);
|
||||
@@ -175,6 +254,11 @@ public class EurekaHealthCheckHandler
|
||||
return STATUS_MAPPING.get(status);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
protected CompositeHealthIndicator getHealthIndicator() {
|
||||
return healthIndicator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
// registered with a high order priority so the close() method is invoked early
|
||||
|
||||
+8
-5
@@ -45,8 +45,8 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator {
|
||||
|
||||
private final EurekaClientConfig clientConfig;
|
||||
|
||||
public EurekaHealthIndicator(EurekaClient eurekaClient, EurekaInstanceConfig instanceConfig,
|
||||
EurekaClientConfig clientConfig) {
|
||||
public EurekaHealthIndicator(EurekaClient eurekaClient,
|
||||
EurekaInstanceConfig instanceConfig, EurekaClientConfig clientConfig) {
|
||||
super();
|
||||
this.eurekaClient = eurekaClient;
|
||||
this.instanceConfig = instanceConfig;
|
||||
@@ -62,7 +62,8 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator {
|
||||
public Health health() {
|
||||
Builder builder = Health.unknown();
|
||||
Status status = getStatus(builder);
|
||||
return builder.status(status).withDetail("applications", getApplications()).build();
|
||||
return builder.status(status).withDetail("applications", getApplications())
|
||||
.build();
|
||||
}
|
||||
|
||||
private Status getStatus(Builder builder) {
|
||||
@@ -79,8 +80,10 @@ public class EurekaHealthIndicator implements DiscoveryHealthIndicator {
|
||||
else if (lastFetch > clientConfig.getRegistryFetchIntervalSeconds() * 2000) {
|
||||
status = new Status("UP",
|
||||
"Eureka discovery client is reporting failures to connect to a Eureka server");
|
||||
builder.withDetail("renewalPeriod", instanceConfig.getLeaseRenewalIntervalInSeconds());
|
||||
builder.withDetail("failCount", lastFetch / clientConfig.getRegistryFetchIntervalSeconds());
|
||||
builder.withDetail("renewalPeriod",
|
||||
instanceConfig.getLeaseRenewalIntervalInSeconds());
|
||||
builder.withDetail("failCount",
|
||||
lastFetch / clientConfig.getRegistryFetchIntervalSeconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+71
-43
@@ -39,7 +39,8 @@ import org.springframework.util.StringUtils;
|
||||
* @author Gregor Zurowski
|
||||
*/
|
||||
@ConfigurationProperties("eureka.instance")
|
||||
public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, EnvironmentAware {
|
||||
public class EurekaInstanceConfigBean
|
||||
implements CloudEurekaInstanceConfig, EnvironmentAware {
|
||||
|
||||
private static final String UNKNOWN = "unknown";
|
||||
|
||||
@@ -155,7 +156,8 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
* Returns the data center this instance is deployed. This information is used to get
|
||||
* some AWS specific instance information if the instance is deployed in AWS.
|
||||
*/
|
||||
private DataCenterInfo dataCenterInfo = new MyDataCenterInfo(DataCenterInfo.Name.MyOwn);
|
||||
private DataCenterInfo dataCenterInfo = new MyDataCenterInfo(
|
||||
DataCenterInfo.Name.MyOwn);
|
||||
|
||||
/**
|
||||
* Get the IPAdress of the instance. This information is for academic purposes only as
|
||||
@@ -329,7 +331,8 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
this.environment = environment;
|
||||
// set some defaults from the environment, but allow the defaults to use relaxed
|
||||
// binding
|
||||
String springAppName = this.environment.getProperty("spring.application.name", "");
|
||||
String springAppName = this.environment.getProperty("spring.application.name",
|
||||
"");
|
||||
if (StringUtils.hasText(springAppName)) {
|
||||
setAppname(springAppName);
|
||||
setVirtualHostName(springAppName);
|
||||
@@ -421,7 +424,8 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
return leaseExpirationDurationInSeconds;
|
||||
}
|
||||
|
||||
public void setLeaseExpirationDurationInSeconds(int leaseExpirationDurationInSeconds) {
|
||||
public void setLeaseExpirationDurationInSeconds(
|
||||
int leaseExpirationDurationInSeconds) {
|
||||
this.leaseExpirationDurationInSeconds = leaseExpirationDurationInSeconds;
|
||||
}
|
||||
|
||||
@@ -574,17 +578,23 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
return false;
|
||||
}
|
||||
EurekaInstanceConfigBean that = (EurekaInstanceConfigBean) o;
|
||||
return Objects.equals(hostInfo, that.hostInfo) && Objects.equals(inetUtils, that.inetUtils)
|
||||
&& Objects.equals(appname, that.appname) && Objects.equals(appGroupName, that.appGroupName)
|
||||
&& instanceEnabledOnit == that.instanceEnabledOnit && nonSecurePort == that.nonSecurePort
|
||||
&& securePort == that.securePort && nonSecurePortEnabled == that.nonSecurePortEnabled
|
||||
return Objects.equals(hostInfo, that.hostInfo)
|
||||
&& Objects.equals(inetUtils, that.inetUtils)
|
||||
&& Objects.equals(appname, that.appname)
|
||||
&& Objects.equals(appGroupName, that.appGroupName)
|
||||
&& instanceEnabledOnit == that.instanceEnabledOnit
|
||||
&& nonSecurePort == that.nonSecurePort && securePort == that.securePort
|
||||
&& nonSecurePortEnabled == that.nonSecurePortEnabled
|
||||
&& securePortEnabled == that.securePortEnabled
|
||||
&& leaseRenewalIntervalInSeconds == that.leaseRenewalIntervalInSeconds
|
||||
&& leaseExpirationDurationInSeconds == that.leaseExpirationDurationInSeconds
|
||||
&& Objects.equals(virtualHostName, that.virtualHostName) && Objects.equals(instanceId, that.instanceId)
|
||||
&& Objects.equals(virtualHostName, that.virtualHostName)
|
||||
&& Objects.equals(instanceId, that.instanceId)
|
||||
&& Objects.equals(secureVirtualHostName, that.secureVirtualHostName)
|
||||
&& Objects.equals(aSGName, that.aSGName) && Objects.equals(metadataMap, that.metadataMap)
|
||||
&& Objects.equals(dataCenterInfo, that.dataCenterInfo) && Objects.equals(ipAddress, that.ipAddress)
|
||||
&& Objects.equals(aSGName, that.aSGName)
|
||||
&& Objects.equals(metadataMap, that.metadataMap)
|
||||
&& Objects.equals(dataCenterInfo, that.dataCenterInfo)
|
||||
&& Objects.equals(ipAddress, that.ipAddress)
|
||||
&& Objects.equals(statusPageUrlPath, that.statusPageUrlPath)
|
||||
&& Objects.equals(statusPageUrl, that.statusPageUrl)
|
||||
&& Objects.equals(homePageUrlPath, that.homePageUrlPath)
|
||||
@@ -592,47 +602,65 @@ public class EurekaInstanceConfigBean implements CloudEurekaInstanceConfig, Envi
|
||||
&& Objects.equals(healthCheckUrlPath, that.healthCheckUrlPath)
|
||||
&& Objects.equals(healthCheckUrl, that.healthCheckUrl)
|
||||
&& Objects.equals(secureHealthCheckUrl, that.secureHealthCheckUrl)
|
||||
&& Objects.equals(namespace, that.namespace) && Objects.equals(hostname, that.hostname)
|
||||
&& preferIpAddress == that.preferIpAddress && Objects.equals(initialStatus, that.initialStatus)
|
||||
&& Arrays.equals(defaultAddressResolutionOrder, that.defaultAddressResolutionOrder)
|
||||
&& Objects.equals(namespace, that.namespace)
|
||||
&& Objects.equals(hostname, that.hostname)
|
||||
&& preferIpAddress == that.preferIpAddress
|
||||
&& Objects.equals(initialStatus, that.initialStatus)
|
||||
&& Arrays.equals(defaultAddressResolutionOrder,
|
||||
that.defaultAddressResolutionOrder)
|
||||
&& Objects.equals(environment, that.environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(hostInfo, inetUtils, appname, appGroupName, instanceEnabledOnit, nonSecurePort, securePort,
|
||||
nonSecurePortEnabled, securePortEnabled, leaseRenewalIntervalInSeconds,
|
||||
leaseExpirationDurationInSeconds, virtualHostName, instanceId, secureVirtualHostName, aSGName,
|
||||
metadataMap, dataCenterInfo, ipAddress, statusPageUrlPath, statusPageUrl, homePageUrlPath, homePageUrl,
|
||||
healthCheckUrlPath, healthCheckUrl, secureHealthCheckUrl, namespace, hostname, preferIpAddress,
|
||||
initialStatus, defaultAddressResolutionOrder, environment);
|
||||
return Objects.hash(hostInfo, inetUtils, appname, appGroupName,
|
||||
instanceEnabledOnit, nonSecurePort, securePort, nonSecurePortEnabled,
|
||||
securePortEnabled, leaseRenewalIntervalInSeconds,
|
||||
leaseExpirationDurationInSeconds, virtualHostName, instanceId,
|
||||
secureVirtualHostName, aSGName, metadataMap, dataCenterInfo, ipAddress,
|
||||
statusPageUrlPath, statusPageUrl, homePageUrlPath, homePageUrl,
|
||||
healthCheckUrlPath, healthCheckUrl, secureHealthCheckUrl, namespace,
|
||||
hostname, preferIpAddress, initialStatus, defaultAddressResolutionOrder,
|
||||
environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("EurekaInstanceConfigBean{").append("hostInfo=").append(hostInfo).append(", ")
|
||||
.append("inetUtils=").append(inetUtils).append(", ").append("appname='").append(appname).append("', ")
|
||||
.append("appGroupName='").append(appGroupName).append("', ").append("instanceEnabledOnit=")
|
||||
.append(instanceEnabledOnit).append(", ").append("nonSecurePort=").append(nonSecurePort).append(", ")
|
||||
.append("securePort=").append(securePort).append(", ").append("nonSecurePortEnabled=")
|
||||
.append(nonSecurePortEnabled).append(", ").append("securePortEnabled=").append(securePortEnabled)
|
||||
.append(", ").append("leaseRenewalIntervalInSeconds=").append(leaseRenewalIntervalInSeconds)
|
||||
.append(", ").append("leaseExpirationDurationInSeconds=").append(leaseExpirationDurationInSeconds)
|
||||
.append(", ").append("virtualHostName='").append(virtualHostName).append("', ").append("instanceId='")
|
||||
.append(instanceId).append("', ").append("secureVirtualHostName='").append(secureVirtualHostName)
|
||||
.append("', ").append("aSGName='").append(aSGName).append("', ").append("metadataMap=")
|
||||
.append(metadataMap).append(", ").append("dataCenterInfo=").append(dataCenterInfo).append(", ")
|
||||
.append("ipAddress='").append(ipAddress).append("', ").append("statusPageUrlPath='")
|
||||
.append(statusPageUrlPath).append("', ").append("statusPageUrl='").append(statusPageUrl).append("', ")
|
||||
.append("homePageUrlPath='").append(homePageUrlPath).append("', ").append("homePageUrl='")
|
||||
.append(homePageUrl).append("', ").append("healthCheckUrlPath='").append(healthCheckUrlPath)
|
||||
.append("', ").append("healthCheckUrl='").append(healthCheckUrl).append("', ")
|
||||
.append("secureHealthCheckUrl='").append(secureHealthCheckUrl).append("', ").append("namespace='")
|
||||
.append(namespace).append("', ").append("hostname='").append(hostname).append("', ")
|
||||
.append("preferIpAddress=").append(preferIpAddress).append(", ").append("initialStatus=")
|
||||
.append(initialStatus).append(", ").append("defaultAddressResolutionOrder=")
|
||||
.append(Arrays.toString(defaultAddressResolutionOrder)).append(", ").append("environment=")
|
||||
.append(environment).append(", ").append("}").toString();
|
||||
return new StringBuilder("EurekaInstanceConfigBean{").append("hostInfo=")
|
||||
.append(hostInfo).append(", ").append("inetUtils=").append(inetUtils)
|
||||
.append(", ").append("appname='").append(appname).append("', ")
|
||||
.append("appGroupName='").append(appGroupName).append("', ")
|
||||
.append("instanceEnabledOnit=").append(instanceEnabledOnit).append(", ")
|
||||
.append("nonSecurePort=").append(nonSecurePort).append(", ")
|
||||
.append("securePort=").append(securePort).append(", ")
|
||||
.append("nonSecurePortEnabled=").append(nonSecurePortEnabled).append(", ")
|
||||
.append("securePortEnabled=").append(securePortEnabled).append(", ")
|
||||
.append("leaseRenewalIntervalInSeconds=")
|
||||
.append(leaseRenewalIntervalInSeconds).append(", ")
|
||||
.append("leaseExpirationDurationInSeconds=")
|
||||
.append(leaseExpirationDurationInSeconds).append(", ")
|
||||
.append("virtualHostName='").append(virtualHostName).append("', ")
|
||||
.append("instanceId='").append(instanceId).append("', ")
|
||||
.append("secureVirtualHostName='").append(secureVirtualHostName)
|
||||
.append("', ").append("aSGName='").append(aSGName).append("', ")
|
||||
.append("metadataMap=").append(metadataMap).append(", ")
|
||||
.append("dataCenterInfo=").append(dataCenterInfo).append(", ")
|
||||
.append("ipAddress='").append(ipAddress).append("', ")
|
||||
.append("statusPageUrlPath='").append(statusPageUrlPath).append("', ")
|
||||
.append("statusPageUrl='").append(statusPageUrl).append("', ")
|
||||
.append("homePageUrlPath='").append(homePageUrlPath).append("', ")
|
||||
.append("homePageUrl='").append(homePageUrl).append("', ")
|
||||
.append("healthCheckUrlPath='").append(healthCheckUrlPath).append("', ")
|
||||
.append("healthCheckUrl='").append(healthCheckUrl).append("', ")
|
||||
.append("secureHealthCheckUrl='").append(secureHealthCheckUrl)
|
||||
.append("', ").append("namespace='").append(namespace).append("', ")
|
||||
.append("hostname='").append(hostname).append("', ")
|
||||
.append("preferIpAddress=").append(preferIpAddress).append(", ")
|
||||
.append("initialStatus=").append(initialStatus).append(", ")
|
||||
.append("defaultAddressResolutionOrder=")
|
||||
.append(Arrays.toString(defaultAddressResolutionOrder)).append(", ")
|
||||
.append("environment=").append(environment).append(", ").append("}")
|
||||
.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+14
-8
@@ -46,18 +46,23 @@ public class InstanceInfoFactory {
|
||||
if (!namespace.endsWith(".")) {
|
||||
namespace = namespace + ".";
|
||||
}
|
||||
builder.setNamespace(namespace).setAppName(config.getAppname()).setInstanceId(config.getInstanceId())
|
||||
.setAppGroupName(config.getAppGroupName()).setDataCenterInfo(config.getDataCenterInfo())
|
||||
builder.setNamespace(namespace).setAppName(config.getAppname())
|
||||
.setInstanceId(config.getInstanceId())
|
||||
.setAppGroupName(config.getAppGroupName())
|
||||
.setDataCenterInfo(config.getDataCenterInfo())
|
||||
.setIPAddr(config.getIpAddress()).setHostName(config.getHostName(false))
|
||||
.setPort(config.getNonSecurePort())
|
||||
.enablePort(InstanceInfo.PortType.UNSECURE, config.isNonSecurePortEnabled())
|
||||
.enablePort(InstanceInfo.PortType.UNSECURE,
|
||||
config.isNonSecurePortEnabled())
|
||||
.setSecurePort(config.getSecurePort())
|
||||
.enablePort(InstanceInfo.PortType.SECURE, config.getSecurePortEnabled())
|
||||
.setVIPAddress(config.getVirtualHostName()).setSecureVIPAddress(config.getSecureVirtualHostName())
|
||||
.setVIPAddress(config.getVirtualHostName())
|
||||
.setSecureVIPAddress(config.getSecureVirtualHostName())
|
||||
.setHomePageUrl(config.getHomePageUrlPath(), config.getHomePageUrl())
|
||||
.setStatusPageUrl(config.getStatusPageUrlPath(), config.getStatusPageUrl())
|
||||
.setHealthCheckUrls(config.getHealthCheckUrlPath(), config.getHealthCheckUrl(),
|
||||
config.getSecureHealthCheckUrl())
|
||||
.setStatusPageUrl(config.getStatusPageUrlPath(),
|
||||
config.getStatusPageUrl())
|
||||
.setHealthCheckUrls(config.getHealthCheckUrlPath(),
|
||||
config.getHealthCheckUrl(), config.getSecureHealthCheckUrl())
|
||||
.setASGName(config.getASGName());
|
||||
|
||||
// Start off with the STARTING state to avoid traffic
|
||||
@@ -70,7 +75,8 @@ public class InstanceInfoFactory {
|
||||
}
|
||||
else {
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Setting initial instance status as: " + InstanceInfo.InstanceStatus.UP
|
||||
log.info("Setting initial instance status as: "
|
||||
+ InstanceInfo.InstanceStatus.UP
|
||||
+ ". This may be too early for the instance to advertise itself as available. "
|
||||
+ "You would instead want to control this via a healthcheck handler.");
|
||||
}
|
||||
|
||||
+28
-32
@@ -34,8 +34,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.MutableDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateDiscoveryClientOptionalArgs;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientDiscoveryClientOptionalArgs;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -48,7 +46,8 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
protected static final Log logger = LogFactory.getLog(DiscoveryClientOptionalArgsConfiguration.class);
|
||||
protected static final Log logger = LogFactory
|
||||
.getLog(DiscoveryClientOptionalArgsConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConfigurationProperties("eureka.client.tls")
|
||||
@@ -57,41 +56,33 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||
@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
|
||||
@ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class }, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
|
||||
havingValue = "false")
|
||||
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier)
|
||||
throws GeneralSecurityException, IOException {
|
||||
@ConditionalOnMissingBean(value = { AbstractDiscoveryClientOptionalArgs.class },
|
||||
search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled",
|
||||
matchIfMissing = true, havingValue = "false")
|
||||
public RestTemplateDiscoveryClientOptionalArgs restTemplateDiscoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties) throws GeneralSecurityException, IOException {
|
||||
logger.info("Eureka HTTP Client uses RestTemplate.");
|
||||
RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs(
|
||||
eurekaClientHttpRequestFactorySupplier);
|
||||
RestTemplateDiscoveryClientOptionalArgs result = new RestTemplateDiscoveryClientOptionalArgs();
|
||||
setupTLS(result, tlsProperties);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.web.client.RestTemplate")
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier() {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "com.sun.jersey.api.client.filter.ClientFilter")
|
||||
@ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class, search = SearchStrategy.CURRENT)
|
||||
public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs(TlsProperties tlsProperties)
|
||||
throws GeneralSecurityException, IOException {
|
||||
@ConditionalOnMissingBean(value = AbstractDiscoveryClientOptionalArgs.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public MutableDiscoveryClientOptionalArgs discoveryClientOptionalArgs(
|
||||
TlsProperties tlsProperties) throws GeneralSecurityException, IOException {
|
||||
logger.info("Eureka HTTP Client uses Jersey");
|
||||
MutableDiscoveryClientOptionalArgs result = new MutableDiscoveryClientOptionalArgs();
|
||||
setupTLS(result, tlsProperties);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void setupTLS(AbstractDiscoveryClientOptionalArgs<?> args, TlsProperties properties)
|
||||
throws GeneralSecurityException, IOException {
|
||||
private static void setupTLS(AbstractDiscoveryClientOptionalArgs<?> args,
|
||||
TlsProperties properties) throws GeneralSecurityException, IOException {
|
||||
if (properties.isEnabled()) {
|
||||
SSLContextFactory factory = new SSLContextFactory(properties);
|
||||
args.setSSLContext(factory.createSSLContext());
|
||||
@@ -99,8 +90,10 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass("com.sun.jersey.api.client.filter.ClientFilter")
|
||||
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")
|
||||
@ConditionalOnClass(
|
||||
name = "org.springframework.web.reactive.function.client.WebClient")
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled",
|
||||
havingValue = "true")
|
||||
protected static class WebClientConfiguration {
|
||||
|
||||
@Autowired
|
||||
@@ -108,10 +101,12 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(
|
||||
value = { AbstractDiscoveryClientOptionalArgs.class, RestTemplateDiscoveryClientOptionalArgs.class },
|
||||
value = { AbstractDiscoveryClientOptionalArgs.class,
|
||||
RestTemplateDiscoveryClientOptionalArgs.class },
|
||||
search = SearchStrategy.CURRENT)
|
||||
public WebClientDiscoveryClientOptionalArgs webClientDiscoveryClientOptionalArgs(
|
||||
ObjectProvider<WebClient.Builder> builder) throws GeneralSecurityException, IOException {
|
||||
ObjectProvider<WebClient.Builder> builder)
|
||||
throws GeneralSecurityException, IOException {
|
||||
logger.info("Eureka HTTP Client uses WebClient.");
|
||||
WebClientDiscoveryClientOptionalArgs result = new WebClientDiscoveryClientOptionalArgs(
|
||||
builder::getIfAvailable);
|
||||
@@ -124,13 +119,14 @@ public class DiscoveryClientOptionalArgsConfiguration {
|
||||
@Configuration
|
||||
@ConditionalOnMissingClass({ "com.sun.jersey.api.client.filter.ClientFilter",
|
||||
"org.springframework.web.reactive.function.client.WebClient" })
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled",
|
||||
havingValue = "true")
|
||||
protected static class WebClientNotFoundConfiguration {
|
||||
|
||||
public WebClientNotFoundConfiguration() {
|
||||
throw new IllegalStateException(
|
||||
"eureka.client.webclient.enabled is true, " + "but WebClient is not on the classpath. Please add "
|
||||
+ "spring-boot-starter-webflux as a dependency.");
|
||||
throw new IllegalStateException("eureka.client.webclient.enabled is true, "
|
||||
+ "but WebClient is not on the classpath. Please add "
|
||||
+ "spring-boot-starter-webflux as a dependency.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -36,7 +36,8 @@ import org.springframework.util.StringUtils;
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
@ConditionalOnClass({ EurekaInstanceConfigBean.class, EurekaClient.class, ConfigServerProperties.class })
|
||||
@ConditionalOnClass({ EurekaInstanceConfigBean.class, EurekaClient.class,
|
||||
ConfigServerProperties.class })
|
||||
public class EurekaClientConfigServerAutoConfiguration {
|
||||
|
||||
@Autowired(required = false)
|
||||
@@ -51,7 +52,8 @@ public class EurekaClientConfigServerAutoConfiguration {
|
||||
return;
|
||||
}
|
||||
String prefix = this.server.getPrefix();
|
||||
if (StringUtils.hasText(prefix) && !StringUtils.hasText(this.instance.getMetadataMap().get("configPath"))) {
|
||||
if (StringUtils.hasText(prefix) && !StringUtils
|
||||
.hasText(this.instance.getMetadataMap().get("configPath"))) {
|
||||
this.instance.getMetadataMap().put("configPath", prefix);
|
||||
}
|
||||
}
|
||||
|
||||
+110
-48
@@ -16,12 +16,21 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.endpoint.EndpointUtils;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -29,21 +38,20 @@ import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.config.client.ConfigServicePropertySourceLocator;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactory;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientEurekaHttpClient;
|
||||
import org.springframework.cloud.netflix.eureka.http.WebClientTransportClientFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
@@ -53,71 +61,125 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ConditionalOnClass(ConfigServicePropertySourceLocator.class)
|
||||
@Conditional(EurekaConfigServerBootstrapConfiguration.EurekaConfigServerBootstrapCondition.class)
|
||||
@ConditionalOnProperty(value = "spring.cloud.config.discovery.enabled",
|
||||
matchIfMissing = false)
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
public class EurekaConfigServerBootstrapConfiguration {
|
||||
|
||||
private static final Log log = LogFactory
|
||||
.getLog(EurekaConfigServerBootstrapConfiguration.class);
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(value = EurekaClientConfig.class, search = SearchStrategy.CURRENT)
|
||||
@ConditionalOnMissingBean(value = EurekaClientConfig.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public EurekaClientConfigBean eurekaClientConfigBean() {
|
||||
return new EurekaClientConfigBean();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(EurekaHttpClient.class)
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", matchIfMissing = true,
|
||||
havingValue = "false")
|
||||
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(EurekaClientConfigBean config,
|
||||
Environment env, @Nullable TlsProperties properties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
return (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory(properties,
|
||||
eurekaClientHttpRequestFactorySupplier)
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled",
|
||||
matchIfMissing = true, havingValue = "false")
|
||||
public RestTemplateEurekaHttpClient configDiscoveryRestTemplateEurekaHttpClient(
|
||||
EurekaClientConfigBean config, Environment env) {
|
||||
return (RestTemplateEurekaHttpClient) new RestTemplateTransportClientFactory()
|
||||
.newClient(new DefaultEndpoint(getEurekaUrl(config, env)));
|
||||
}
|
||||
|
||||
private static String getEurekaUrl(EurekaClientConfigBean config, Environment env) {
|
||||
List<String> urls = EndpointUtils.getDiscoveryServiceUrls(config,
|
||||
EurekaClientConfigBean.DEFAULT_ZONE, new HostnameBasedUrlRandomizer(
|
||||
env.getProperty("eureka.instance.hostname")));
|
||||
return urls.get(0);
|
||||
}
|
||||
|
||||
private boolean isSuccessful(EurekaHttpResponse<Applications> response) {
|
||||
HttpStatus httpStatus = HttpStatus.resolve(response.getStatusCode());
|
||||
return httpStatus != null && httpStatus.is2xxSuccessful();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
EurekaClientHttpRequestFactorySupplier defaultEurekaClientHttpRequestFactorySupplier() {
|
||||
return new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
public ConfigServerInstanceProvider.Function eurekaConfigServerInstanceProvider(
|
||||
EurekaHttpClient client, EurekaClientConfig config) {
|
||||
|
||||
return serviceId -> {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider finding instances for "
|
||||
+ serviceId);
|
||||
}
|
||||
EurekaHttpResponse<Applications> response = client
|
||||
.getApplications(config.getRegion());
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!isSuccessful(response) || response.getEntity() == null) {
|
||||
return instances;
|
||||
}
|
||||
|
||||
Applications applications = response.getEntity();
|
||||
applications.shuffleInstances(config.shouldFilterOnlyUpInstances());
|
||||
List<InstanceInfo> infos = applications
|
||||
.getInstancesByVirtualHostName(serviceId);
|
||||
for (InstanceInfo info : infos) {
|
||||
instances.add(new EurekaServiceInstance(info));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider found " + infos.size()
|
||||
+ " instance(s) for " + serviceId + ", " + instances);
|
||||
}
|
||||
return instances;
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConfigServerInstanceProvider.Function eurekaConfigServerInstanceProvider(EurekaHttpClient client,
|
||||
EurekaClientConfig config) {
|
||||
return new EurekaConfigServerInstanceProvider(client, config)::getInstances;
|
||||
private static final class HostnameBasedUrlRandomizer
|
||||
implements EndpointUtils.ServiceUrlRandomizer {
|
||||
|
||||
private final String hostname;
|
||||
|
||||
private HostnameBasedUrlRandomizer(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomize(List<String> urlList) {
|
||||
int listSize = 0;
|
||||
if (urlList != null) {
|
||||
listSize = urlList.size();
|
||||
}
|
||||
if (!StringUtils.hasText(hostname) || listSize == 0) {
|
||||
return;
|
||||
}
|
||||
// Find the hashcode of the instance hostname and use it to find an entry
|
||||
// and then arrange the rest of the entries after this entry.
|
||||
int instanceHashcode = hostname.hashCode();
|
||||
if (instanceHashcode < 0) {
|
||||
instanceHashcode = instanceHashcode * -1;
|
||||
}
|
||||
int backupInstance = instanceHashcode % listSize;
|
||||
for (int i = 0; i < backupInstance; i++) {
|
||||
String zone = urlList.remove(0);
|
||||
urlList.add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(name = "org.springframework.web.reactive.function.client.WebClient")
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled", havingValue = "true")
|
||||
@ImportAutoConfiguration({ CodecsAutoConfiguration.class, WebClientAutoConfiguration.class })
|
||||
@ConditionalOnClass(
|
||||
name = "org.springframework.web.reactive.function.client.WebClient")
|
||||
@ConditionalOnProperty(prefix = "eureka.client", name = "webclient.enabled",
|
||||
havingValue = "true")
|
||||
@ImportAutoConfiguration({ CodecsAutoConfiguration.class,
|
||||
WebClientAutoConfiguration.class })
|
||||
protected static class WebClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(EurekaHttpClient.class)
|
||||
public WebClientEurekaHttpClient configDiscoveryWebClientEurekaHttpClient(EurekaClientConfigBean config,
|
||||
ObjectProvider<WebClient.Builder> builder, Environment env) {
|
||||
return (WebClientEurekaHttpClient) new WebClientTransportClientFactory(builder::getIfAvailable)
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, env));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class EurekaConfigServerBootstrapCondition extends AllNestedConditions {
|
||||
|
||||
EurekaConfigServerBootstrapCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty("spring.cloud.config.discovery.enabled")
|
||||
static class OnCloudConfigProperty {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
|
||||
static class OnEurekaClient {
|
||||
|
||||
public WebClientEurekaHttpClient configDiscoveryWebClientEurekaHttpClient(
|
||||
EurekaClientConfigBean config, ObjectProvider<WebClient.Builder> builder,
|
||||
Environment env) {
|
||||
return (WebClientEurekaHttpClient) new WebClientTransportClientFactory(
|
||||
builder::getIfAvailable)
|
||||
.newClient(new DefaultEndpoint(getEurekaUrl(config, env)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-69
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
|
||||
import org.springframework.boot.BootstrapRegistry;
|
||||
import org.springframework.boot.BootstrapRegistryInitializer;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.config.client.ConfigClientProperties;
|
||||
import org.springframework.cloud.config.client.ConfigServerInstanceProvider;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.cloud.netflix.eureka.http.DefaultEurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.EurekaClientHttpRequestFactorySupplier;
|
||||
import org.springframework.cloud.netflix.eureka.http.RestTemplateTransportClientFactory;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
public class EurekaConfigServerBootstrapper implements BootstrapRegistryInitializer {
|
||||
|
||||
@Override
|
||||
public void initialize(BootstrapRegistry registry) {
|
||||
if (!ClassUtils.isPresent("org.springframework.cloud.config.client.ConfigServerInstanceProvider", null)) {
|
||||
return;
|
||||
}
|
||||
registry.registerIfAbsent(EurekaClientConfigBean.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return binder.bind(EurekaClientConfigBean.PREFIX, EurekaClientConfigBean.class)
|
||||
.orElseGet(EurekaClientConfigBean::new);
|
||||
});
|
||||
|
||||
registry.registerIfAbsent(ConfigServerInstanceProvider.Function.class, context -> {
|
||||
Binder binder = context.get(Binder.class);
|
||||
if (!getDiscoveryEnabled(binder)) {
|
||||
return null;
|
||||
}
|
||||
EurekaClientConfigBean config = context.get(EurekaClientConfigBean.class);
|
||||
EurekaHttpClient httpClient = new RestTemplateTransportClientFactory(
|
||||
context.getOrElse(TlsProperties.class, null),
|
||||
context.getOrElse(EurekaClientHttpRequestFactorySupplier.class,
|
||||
new DefaultEurekaClientHttpRequestFactorySupplier()))
|
||||
.newClient(HostnameBasedUrlRandomizer.randomEndpoint(config, binder));
|
||||
return new EurekaConfigServerInstanceProvider(httpClient, config)::getInstances;
|
||||
});
|
||||
}
|
||||
|
||||
private Boolean getDiscoveryEnabled(Binder binder) {
|
||||
return binder.bind(ConfigClientProperties.CONFIG_DISCOVERY_ENABLED, Boolean.class).orElse(false);
|
||||
}
|
||||
|
||||
}
|
||||
-80
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.shared.Applications;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpResponse;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaServiceInstance;
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
public class EurekaConfigServerInstanceProvider {
|
||||
|
||||
private final Log log;
|
||||
|
||||
private final EurekaHttpClient client;
|
||||
|
||||
private final EurekaClientConfig config;
|
||||
|
||||
public EurekaConfigServerInstanceProvider(EurekaHttpClient client, EurekaClientConfig config) {
|
||||
this(LogFactory.getLog(EurekaConfigServerInstanceProvider.class), client, config);
|
||||
}
|
||||
|
||||
public EurekaConfigServerInstanceProvider(Log log, EurekaHttpClient client, EurekaClientConfig config) {
|
||||
this.log = log;
|
||||
this.client = client;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public List<ServiceInstance> getInstances(String serviceId) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider finding instances for " + serviceId);
|
||||
}
|
||||
EurekaHttpResponse<Applications> response = client.getApplications(config.getRegion());
|
||||
List<ServiceInstance> instances = new ArrayList<>();
|
||||
if (!isSuccessful(response) || response.getEntity() == null) {
|
||||
return instances;
|
||||
}
|
||||
|
||||
Applications applications = response.getEntity();
|
||||
applications.shuffleInstances(config.shouldFilterOnlyUpInstances());
|
||||
List<InstanceInfo> infos = applications.getInstancesByVirtualHostName(serviceId);
|
||||
for (InstanceInfo info : infos) {
|
||||
instances.add(new EurekaServiceInstance(info));
|
||||
}
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("eurekaConfigServerInstanceProvider found " + infos.size() + " instance(s) for " + serviceId
|
||||
+ ", " + instances);
|
||||
}
|
||||
return instances;
|
||||
}
|
||||
|
||||
private boolean isSuccessful(EurekaHttpResponse<Applications> response) {
|
||||
HttpStatus httpStatus = HttpStatus.resolve(response.getStatusCode());
|
||||
return httpStatus != null && httpStatus.is2xxSuccessful();
|
||||
}
|
||||
|
||||
}
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.config;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.discovery.endpoint.EndpointUtils;
|
||||
import com.netflix.discovery.shared.resolver.DefaultEndpoint;
|
||||
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.cloud.netflix.eureka.EurekaClientConfigBean;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
final class HostnameBasedUrlRandomizer implements EndpointUtils.ServiceUrlRandomizer {
|
||||
|
||||
private final String hostname;
|
||||
|
||||
HostnameBasedUrlRandomizer(String hostname) {
|
||||
this.hostname = hostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void randomize(List<String> urlList) {
|
||||
int listSize = 0;
|
||||
if (urlList != null) {
|
||||
listSize = urlList.size();
|
||||
}
|
||||
if (!StringUtils.hasText(hostname) || listSize == 0) {
|
||||
return;
|
||||
}
|
||||
// Find the hashcode of the instance hostname and use it to find an entry
|
||||
// and then arrange the rest of the entries after this entry.
|
||||
int instanceHashcode = hostname.hashCode();
|
||||
if (instanceHashcode < 0) {
|
||||
instanceHashcode = instanceHashcode * -1;
|
||||
}
|
||||
int backupInstance = instanceHashcode % listSize;
|
||||
for (int i = 0; i < backupInstance; i++) {
|
||||
String zone = urlList.remove(0);
|
||||
urlList.add(zone);
|
||||
}
|
||||
}
|
||||
|
||||
static String getEurekaUrl(EurekaClientConfigBean config, String hostname) {
|
||||
List<String> urls = EndpointUtils.getDiscoveryServiceUrls(config, EurekaClientConfigBean.DEFAULT_ZONE,
|
||||
new HostnameBasedUrlRandomizer(hostname));
|
||||
return urls.get(0);
|
||||
}
|
||||
|
||||
static DefaultEndpoint randomEndpoint(EurekaClientConfigBean config, Environment env) {
|
||||
String hostname = env.getProperty("eureka.instance.hostname");
|
||||
return new DefaultEndpoint(getEurekaUrl(config, hostname));
|
||||
}
|
||||
|
||||
static DefaultEndpoint randomEndpoint(EurekaClientConfigBean config, Binder binder) {
|
||||
String hostname = binder.bind("eureka.instance.hostname", String.class).orElseGet(() -> null);
|
||||
return new DefaultEndpoint(getEurekaUrl(config, hostname));
|
||||
}
|
||||
|
||||
}
|
||||
-54
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Supplier for the {@link ClientHttpRequestFactory} to be used by Eureka client that uses
|
||||
* {@link HttpClients}.
|
||||
*
|
||||
* @author Marcin Grzejszczak
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public class DefaultEurekaClientHttpRequestFactorySupplier implements EurekaClientHttpRequestFactorySupplier {
|
||||
|
||||
@Override
|
||||
public ClientHttpRequestFactory get(SSLContext sslContext, @Nullable HostnameVerifier hostnameVerifier) {
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
if (sslContext != null) {
|
||||
httpClientBuilder = httpClientBuilder.setSSLContext(sslContext);
|
||||
}
|
||||
if (hostnameVerifier != null) {
|
||||
httpClientBuilder = httpClientBuilder.setSSLHostnameVerifier(hostnameVerifier);
|
||||
}
|
||||
CloseableHttpClient httpClient = httpClientBuilder.build();
|
||||
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
requestFactory.setHttpClient(httpClient);
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-15
@@ -21,23 +21,11 @@ import com.netflix.discovery.AbstractDiscoveryClientOptionalArgs;
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class RestTemplateDiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
public class RestTemplateDiscoveryClientOptionalArgs
|
||||
extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
|
||||
protected final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
public RestTemplateDiscoveryClientOptionalArgs(
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
setTransportClientFactories(new RestTemplateTransportClientFactories(this));
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - use
|
||||
* {@link RestTemplateDiscoveryClientOptionalArgs#RestTemplateDiscoveryClientOptionalArgs(EurekaClientHttpRequestFactorySupplier)}
|
||||
*/
|
||||
@Deprecated
|
||||
public RestTemplateDiscoveryClientOptionalArgs() {
|
||||
this(new DefaultEurekaClientHttpRequestFactorySupplier());
|
||||
setTransportClientFactories(new RestTemplateTransportClientFactories());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+57
-39
@@ -74,33 +74,38 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
headers.add(HttpHeaders.ACCEPT_ENCODING, "gzip");
|
||||
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST, new HttpEntity<>(info, headers),
|
||||
Void.class);
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.POST,
|
||||
new HttpEntity<>(info, headers), Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue())
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> cancel(String appName, String id) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id;
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class);
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE,
|
||||
null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue())
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info,
|
||||
InstanceStatus overriddenStatus) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status=" + info.getStatus().toString()
|
||||
+ "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString()
|
||||
+ (overriddenStatus != null ? "&overriddenstatus=" + overriddenStatus.name() : "");
|
||||
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
|
||||
InstanceInfo info, InstanceStatus overriddenStatus) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id + "?status="
|
||||
+ info.getStatus().toString() + "&lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString() + (overriddenStatus != null
|
||||
? "&overriddenstatus=" + overriddenStatus.name() : "");
|
||||
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath, HttpMethod.PUT, null,
|
||||
InstanceInfo.class);
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath,
|
||||
HttpMethod.PUT, null, InstanceInfo.class);
|
||||
|
||||
EurekaHttpResponseBuilder<InstanceInfo> eurekaResponseBuilder = anEurekaHttpResponse(
|
||||
response.getStatusCodeValue(), InstanceInfo.class).headers(headersOf(response));
|
||||
response.getStatusCodeValue(), InstanceInfo.class)
|
||||
.headers(headersOf(response));
|
||||
|
||||
if (response.hasBody()) {
|
||||
eurekaResponseBuilder.entity(response.getBody());
|
||||
@@ -110,24 +115,30 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus,
|
||||
InstanceInfo info) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id + "/status?value=" + newStatus.name()
|
||||
+ "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString();
|
||||
public EurekaHttpResponse<Void> statusUpdate(String appName, String id,
|
||||
InstanceStatus newStatus, InstanceInfo info) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id + "/status?value="
|
||||
+ newStatus.name() + "&lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.PUT, null, Void.class);
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.PUT,
|
||||
null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue())
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id + "/status?lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id,
|
||||
InstanceInfo info) {
|
||||
String urlPath = serviceUrl + "apps/" + appName + '/' + id
|
||||
+ "/status?lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString();
|
||||
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE, null, Void.class);
|
||||
ResponseEntity<Void> response = restTemplate.exchange(urlPath, HttpMethod.DELETE,
|
||||
null, Void.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue()).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue())
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,19 +146,22 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
return getApplicationsInternal("apps/", regions);
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) {
|
||||
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath,
|
||||
String[] regions) {
|
||||
String url = serviceUrl + urlPath;
|
||||
|
||||
if (regions != null && regions.length > 0) {
|
||||
url = url + (urlPath.contains("?") ? "&" : "?") + "regions=" + StringUtil.join(regions);
|
||||
url = url + (urlPath.contains("?") ? "&" : "?") + "regions="
|
||||
+ StringUtil.join(regions);
|
||||
}
|
||||
|
||||
ResponseEntity<EurekaApplications> response = restTemplate.exchange(url, HttpMethod.GET, null,
|
||||
EurekaApplications.class);
|
||||
ResponseEntity<EurekaApplications> response = restTemplate.exchange(url,
|
||||
HttpMethod.GET, null, EurekaApplications.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue(),
|
||||
response.getStatusCode().value() == HttpStatus.OK.value() && response.hasBody()
|
||||
? (Applications) response.getBody() : null).headers(headersOf(response)).build();
|
||||
response.getStatusCode().value() == HttpStatus.OK.value()
|
||||
&& response.hasBody() ? (Applications) response.getBody() : null)
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -161,7 +175,8 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions) {
|
||||
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress,
|
||||
String... regions) {
|
||||
return getApplicationsInternal("svips/" + secureVipAddress, regions);
|
||||
}
|
||||
|
||||
@@ -169,12 +184,14 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
public EurekaHttpResponse<Application> getApplication(String appName) {
|
||||
String urlPath = serviceUrl + "apps/" + appName;
|
||||
|
||||
ResponseEntity<Application> response = restTemplate.exchange(urlPath, HttpMethod.GET, null, Application.class);
|
||||
ResponseEntity<Application> response = restTemplate.exchange(urlPath,
|
||||
HttpMethod.GET, null, Application.class);
|
||||
|
||||
Application application = response.getStatusCodeValue() == HttpStatus.OK.value() && response.hasBody()
|
||||
? response.getBody() : null;
|
||||
Application application = response.getStatusCodeValue() == HttpStatus.OK.value()
|
||||
&& response.hasBody() ? response.getBody() : null;
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue(), application).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue(), application)
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -190,12 +207,13 @@ public class RestTemplateEurekaHttpClient implements EurekaHttpClient {
|
||||
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String urlPath) {
|
||||
urlPath = serviceUrl + urlPath;
|
||||
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath, HttpMethod.GET, null,
|
||||
InstanceInfo.class);
|
||||
ResponseEntity<InstanceInfo> response = restTemplate.exchange(urlPath,
|
||||
HttpMethod.GET, null, InstanceInfo.class);
|
||||
|
||||
return anEurekaHttpResponse(response.getStatusCodeValue(),
|
||||
response.getStatusCodeValue() == HttpStatus.OK.value() && response.hasBody() ? response.getBody()
|
||||
: null).headers(headersOf(response)).build();
|
||||
response.getStatusCodeValue() == HttpStatus.OK.value()
|
||||
&& response.hasBody() ? response.getBody() : null)
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+13
-17
@@ -31,33 +31,29 @@ import com.netflix.discovery.shared.transport.jersey.TransportClientFactories;
|
||||
/**
|
||||
* @author Daniel Lavoie
|
||||
*/
|
||||
public class RestTemplateTransportClientFactories implements TransportClientFactories<Void> {
|
||||
|
||||
private final RestTemplateDiscoveryClientOptionalArgs args;
|
||||
|
||||
public RestTemplateTransportClientFactories(RestTemplateDiscoveryClientOptionalArgs args) {
|
||||
this.args = args;
|
||||
}
|
||||
public class RestTemplateTransportClientFactories
|
||||
implements TransportClientFactories<Void> {
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(Collection<Void> additionalFilters,
|
||||
EurekaJerseyClient providedJerseyClient) {
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
Collection<Void> additionalFilters, EurekaJerseyClient providedJerseyClient) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(EurekaClientConfig clientConfig,
|
||||
Collection<Void> additionalFilters, InstanceInfo myInstanceInfo) {
|
||||
return new RestTemplateTransportClientFactory(this.args.getSSLContext(), this.args.getHostnameVerifier(),
|
||||
this.args.eurekaClientHttpRequestFactorySupplier);
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
EurekaClientConfig clientConfig, Collection<Void> additionalFilters,
|
||||
InstanceInfo myInstanceInfo) {
|
||||
return new RestTemplateTransportClientFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
final EurekaClientConfig clientConfig,
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new RestTemplateTransportClientFactory(this.args.getSSLContext(), this.args.getHostnameVerifier(),
|
||||
this.args.eurekaClientHttpRequestFactorySupplier);
|
||||
final Optional<SSLContext> sslContext,
|
||||
final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new RestTemplateTransportClientFactory();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+17
-64
@@ -18,10 +18,6 @@ package org.springframework.cloud.netflix.eureka.http;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
@@ -42,10 +38,7 @@ import com.netflix.discovery.shared.resolver.EurekaEndpoint;
|
||||
import com.netflix.discovery.shared.transport.EurekaHttpClient;
|
||||
import com.netflix.discovery.shared.transport.TransportClientFactory;
|
||||
|
||||
import org.springframework.cloud.configuration.SSLContextFactory;
|
||||
import org.springframework.cloud.configuration.TlsProperties;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.support.BasicAuthenticationInterceptor;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.client.DefaultResponseErrorHandler;
|
||||
@@ -60,60 +53,21 @@ import org.springframework.web.client.RestTemplate;
|
||||
*/
|
||||
public class RestTemplateTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
private final Optional<SSLContext> sslContext;
|
||||
|
||||
private final Optional<HostnameVerifier> hostnameVerifier;
|
||||
|
||||
private final EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier;
|
||||
|
||||
public RestTemplateTransportClientFactory(TlsProperties tlsProperties,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this.sslContext = context(tlsProperties);
|
||||
this.hostnameVerifier = Optional.empty();
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
}
|
||||
|
||||
private Optional<SSLContext> context(TlsProperties properties) {
|
||||
if (properties == null || !properties.isEnabled()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
try {
|
||||
return Optional.of(new SSLContextFactory(properties).createSSLContext());
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory(Optional<SSLContext> sslContext,
|
||||
Optional<HostnameVerifier> hostnameVerifier,
|
||||
EurekaClientHttpRequestFactorySupplier eurekaClientHttpRequestFactorySupplier) {
|
||||
this.sslContext = sslContext;
|
||||
this.hostnameVerifier = hostnameVerifier;
|
||||
this.eurekaClientHttpRequestFactorySupplier = eurekaClientHttpRequestFactorySupplier;
|
||||
}
|
||||
|
||||
public RestTemplateTransportClientFactory() {
|
||||
this.sslContext = Optional.empty();
|
||||
this.hostnameVerifier = Optional.empty();
|
||||
this.eurekaClientHttpRequestFactorySupplier = new DefaultEurekaClientHttpRequestFactorySupplier();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpClient newClient(EurekaEndpoint serviceUrl) {
|
||||
return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()), serviceUrl.getServiceUrl());
|
||||
return new RestTemplateEurekaHttpClient(restTemplate(serviceUrl.getServiceUrl()),
|
||||
serviceUrl.getServiceUrl());
|
||||
}
|
||||
|
||||
private RestTemplate restTemplate(String serviceUrl) {
|
||||
RestTemplate restTemplate = restTemplate();
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
try {
|
||||
URI serviceURI = new URI(serviceUrl);
|
||||
if (serviceURI.getUserInfo() != null) {
|
||||
String[] credentials = serviceURI.getUserInfo().split(":");
|
||||
if (credentials.length == 2) {
|
||||
restTemplate.getInterceptors()
|
||||
.add(new BasicAuthenticationInterceptor(credentials[0], credentials[1]));
|
||||
restTemplate.getInterceptors().add(new BasicAuthenticationInterceptor(
|
||||
credentials[0], credentials[1]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,12 +81,6 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
private RestTemplate restTemplate() {
|
||||
ClientHttpRequestFactory requestFactory = this.eurekaClientHttpRequestFactorySupplier
|
||||
.get(this.sslContext.orElse(null), this.hostnameVerifier.orElse(null));
|
||||
return new RestTemplate(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the serialization configurations required by the Eureka Server. JSON
|
||||
* content exchanged with eureka requires a root node matching the entity being
|
||||
@@ -145,7 +93,8 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
*/
|
||||
public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
converter.setObjectMapper(new ObjectMapper().setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE));
|
||||
converter.setObjectMapper(new ObjectMapper()
|
||||
.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE));
|
||||
|
||||
SimpleModule jsonModule = new SimpleModule();
|
||||
jsonModule.setSerializerModifier(createJsonSerializerModifier()); // keyFormatter,
|
||||
@@ -153,9 +102,12 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
converter.getObjectMapper().registerModule(jsonModule);
|
||||
|
||||
converter.getObjectMapper().configure(SerializationFeature.WRAP_ROOT_VALUE, true);
|
||||
converter.getObjectMapper().configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
|
||||
converter.getObjectMapper().addMixIn(Applications.class, ApplicationsJsonMixIn.class);
|
||||
converter.getObjectMapper().addMixIn(InstanceInfo.class, InstanceInfoJsonMixIn.class);
|
||||
converter.getObjectMapper().configure(DeserializationFeature.UNWRAP_ROOT_VALUE,
|
||||
true);
|
||||
converter.getObjectMapper().addMixIn(Applications.class,
|
||||
ApplicationsJsonMixIn.class);
|
||||
converter.getObjectMapper().addMixIn(InstanceInfo.class,
|
||||
InstanceInfoJsonMixIn.class);
|
||||
|
||||
// converter.getObjectMapper().addMixIn(DataCenterInfo.class,
|
||||
// DataCenterInfoXmlMixIn.class);
|
||||
@@ -178,15 +130,16 @@ public class RestTemplateTransportClientFactory implements TransportClientFactor
|
||||
// {
|
||||
return new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
|
||||
JsonSerializer<?> serializer) {
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config,
|
||||
BeanDescription beanDesc, JsonSerializer<?> serializer) {
|
||||
/*
|
||||
* if (beanDesc.getBeanClass().isAssignableFrom(Applications.class)) {
|
||||
* return new ApplicationsJsonBeanSerializer((BeanSerializerBase)
|
||||
* serializer, keyFormatter); }
|
||||
*/
|
||||
if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
|
||||
return new InstanceInfoJsonBeanSerializer((BeanSerializerBase) serializer, false);
|
||||
return new InstanceInfoJsonBeanSerializer(
|
||||
(BeanSerializerBase) serializer, false);
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
|
||||
+7
-1
@@ -26,7 +26,13 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @author Daniel Lavoie
|
||||
* @author Haytham Mohamed
|
||||
*/
|
||||
public class WebClientDiscoveryClientOptionalArgs extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
public class WebClientDiscoveryClientOptionalArgs
|
||||
extends AbstractDiscoveryClientOptionalArgs<Void> {
|
||||
|
||||
@Deprecated
|
||||
public WebClientDiscoveryClientOptionalArgs() {
|
||||
this(WebClient::builder);
|
||||
}
|
||||
|
||||
public WebClientDiscoveryClientOptionalArgs(Supplier<WebClient.Builder> builder) {
|
||||
setTransportClientFactories(new WebClientTransportClientFactories(builder));
|
||||
|
||||
+53
-35
@@ -56,10 +56,11 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> register(InstanceInfo info) {
|
||||
return webClient.post().uri("apps/" + info.getAppName(), Void.class).body(BodyInserters.fromValue(info))
|
||||
return webClient.post().uri("apps/" + info.getAppName(), Void.class)
|
||||
.body(BodyInserters.fromValue(info))
|
||||
.header(HttpHeaders.ACCEPT_ENCODING, "gzip")
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.exchange().map(response -> eurekaHttpResponse(response)).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,18 +70,21 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id, InstanceInfo info,
|
||||
InstanceStatus overriddenStatus) {
|
||||
String urlPath = "apps/" + appName + '/' + id + "?status=" + info.getStatus().toString()
|
||||
+ "&lastDirtyTimestamp=" + info.getLastDirtyTimestamp().toString()
|
||||
+ (overriddenStatus != null ? "&overriddenstatus=" + overriddenStatus.name() : "");
|
||||
public EurekaHttpResponse<InstanceInfo> sendHeartBeat(String appName, String id,
|
||||
InstanceInfo info, InstanceStatus overriddenStatus) {
|
||||
String urlPath = "apps/" + appName + '/' + id + "?status="
|
||||
+ info.getStatus().toString() + "&lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString() + (overriddenStatus != null
|
||||
? "&overriddenstatus=" + overriddenStatus.name() : "");
|
||||
|
||||
ClientResponse response = webClient.put().uri(urlPath, InstanceInfo.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.block();
|
||||
|
||||
EurekaHttpResponseBuilder<InstanceInfo> builder = anEurekaHttpResponse(statusCodeValueOf(response),
|
||||
InstanceInfo.class).headers(headersOf(response));
|
||||
EurekaHttpResponseBuilder<InstanceInfo> builder = anEurekaHttpResponse(
|
||||
statusCodeValueOf(response), InstanceInfo.class)
|
||||
.headers(headersOf(response));
|
||||
|
||||
InstanceInfo entity = response.toEntity(InstanceInfo.class).block().getBody();
|
||||
|
||||
@@ -93,24 +97,26 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> statusUpdate(String appName, String id, InstanceStatus newStatus,
|
||||
InstanceInfo info) {
|
||||
String urlPath = "apps/" + appName + '/' + id + "/status?value=" + newStatus.name() + "&lastDirtyTimestamp="
|
||||
public EurekaHttpResponse<Void> statusUpdate(String appName, String id,
|
||||
InstanceStatus newStatus, InstanceInfo info) {
|
||||
String urlPath = "apps/" + appName + '/' + id + "/status?value="
|
||||
+ newStatus.name() + "&lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
|
||||
return webClient.put().uri(urlPath, Void.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.exchange().map(response -> eurekaHttpResponse(response)).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id, InstanceInfo info) {
|
||||
public EurekaHttpResponse<Void> deleteStatusOverride(String appName, String id,
|
||||
InstanceInfo info) {
|
||||
String urlPath = "apps/" + appName + '/' + id + "/status?lastDirtyTimestamp="
|
||||
+ info.getLastDirtyTimestamp().toString();
|
||||
|
||||
return webClient.delete().uri(urlPath, Void.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.map(response -> eurekaHttpResponse(response)).block();
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.exchange().map(response -> eurekaHttpResponse(response)).block();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,23 +124,27 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
return getApplicationsInternal("apps/", regions);
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath, String[] regions) {
|
||||
private EurekaHttpResponse<Applications> getApplicationsInternal(String urlPath,
|
||||
String[] regions) {
|
||||
String url = urlPath;
|
||||
|
||||
if (regions != null && regions.length > 0) {
|
||||
url = url + (urlPath.contains("?") ? "&" : "?") + "regions=" + StringUtil.join(regions);
|
||||
url = url + (urlPath.contains("?") ? "&" : "?") + "regions="
|
||||
+ StringUtil.join(regions);
|
||||
}
|
||||
|
||||
ClientResponse response = webClient.get().uri(url, Applications.class)
|
||||
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
|
||||
Applications body = response.toEntity(Applications.class).block().getBody();
|
||||
|
||||
return anEurekaHttpResponse(statusCode, statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(statusCode,
|
||||
statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,22 +158,27 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress, String... regions) {
|
||||
public EurekaHttpResponse<Applications> getSecureVip(String secureVipAddress,
|
||||
String... regions) {
|
||||
return getApplicationsInternal("svips/" + secureVipAddress, regions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EurekaHttpResponse<Application> getApplication(String appName) {
|
||||
|
||||
ClientResponse response = webClient.get().uri("apps/" + appName, Application.class)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
ClientResponse response = webClient.get()
|
||||
.uri("apps/" + appName, Application.class)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
Application body = response.toEntity(Application.class).block().getBody();
|
||||
|
||||
Application application = statusCode == HttpStatus.OK.value() && body != null ? body : null;
|
||||
Application application = statusCode == HttpStatus.OK.value() && body != null
|
||||
? body : null;
|
||||
|
||||
return anEurekaHttpResponse(statusCode, application).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(statusCode, application).headers(headersOf(response))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -178,13 +193,15 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
|
||||
private EurekaHttpResponse<InstanceInfo> getInstanceInternal(String urlPath) {
|
||||
ClientResponse response = webClient.get().uri(urlPath, InstanceInfo.class)
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange().block();
|
||||
.header(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE).exchange()
|
||||
.block();
|
||||
|
||||
int statusCode = statusCodeValueOf(response);
|
||||
InstanceInfo body = response.toEntity(InstanceInfo.class).block().getBody();
|
||||
|
||||
return anEurekaHttpResponse(statusCode, statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(statusCode,
|
||||
statusCode == HttpStatus.OK.value() && body != null ? body : null)
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -206,8 +223,8 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
asHeaders.entrySet().stream()
|
||||
.forEach(entry -> entry.getValue().stream().forEach(v -> headers.put(entry.getKey(), v)));
|
||||
asHeaders.entrySet().stream().forEach(entry -> entry.getValue().stream()
|
||||
.forEach(v -> headers.put(entry.getKey(), v)));
|
||||
return headers;
|
||||
}
|
||||
|
||||
@@ -216,7 +233,8 @@ public class WebClientEurekaHttpClient implements EurekaHttpClient {
|
||||
}
|
||||
|
||||
private EurekaHttpResponse<Void> eurekaHttpResponse(ClientResponse response) {
|
||||
return anEurekaHttpResponse(statusCodeValueOf(response)).headers(headersOf(response)).build();
|
||||
return anEurekaHttpResponse(statusCodeValueOf(response))
|
||||
.headers(headersOf(response)).build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+9
-6
@@ -44,21 +44,24 @@ public class WebClientTransportClientFactories implements TransportClientFactori
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(Collection<Void> additionalFilters,
|
||||
EurekaJerseyClient providedJerseyClient) {
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
Collection<Void> additionalFilters, EurekaJerseyClient providedJerseyClient) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(EurekaClientConfig clientConfig,
|
||||
Collection<Void> additionalFilters, InstanceInfo myInstanceInfo) {
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
EurekaClientConfig clientConfig, Collection<Void> additionalFilters,
|
||||
InstanceInfo myInstanceInfo) {
|
||||
return new WebClientTransportClientFactory(builder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransportClientFactory newTransportClientFactory(final EurekaClientConfig clientConfig,
|
||||
public TransportClientFactory newTransportClientFactory(
|
||||
final EurekaClientConfig clientConfig,
|
||||
final Collection<Void> additionalFilters, final InstanceInfo myInstanceInfo,
|
||||
final Optional<SSLContext> sslContext, final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
final Optional<SSLContext> sslContext,
|
||||
final Optional<HostnameVerifier> hostnameVerifier) {
|
||||
return new WebClientTransportClientFactory(builder);
|
||||
}
|
||||
|
||||
|
||||
+61
-28
@@ -45,6 +45,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.codec.ClientCodecConfigurer;
|
||||
import org.springframework.http.codec.json.Jackson2JsonDecoder;
|
||||
import org.springframework.http.codec.json.Jackson2JsonEncoder;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunction;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFilterFunctions;
|
||||
@@ -62,6 +63,11 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
|
||||
private final Supplier<WebClient.Builder> builderSupplier;
|
||||
|
||||
@Deprecated
|
||||
public WebClientTransportClientFactory() {
|
||||
this(WebClient::builder);
|
||||
}
|
||||
|
||||
public WebClientTransportClientFactory(Supplier<WebClient.Builder> builderSupplier) {
|
||||
this.builderSupplier = builderSupplier;
|
||||
}
|
||||
@@ -83,8 +89,10 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
if (serviceURI.getUserInfo() != null) {
|
||||
String[] credentials = serviceURI.getUserInfo().split(":");
|
||||
if (credentials.length == 2) {
|
||||
builder.filter(ExchangeFilterFunctions.basicAuthentication(credentials[0], credentials[1]));
|
||||
url = serviceUrl.replace(credentials[0] + ":" + credentials[1] + "@", "");
|
||||
builder.filter(ExchangeFilterFunctions
|
||||
.basicAuthentication(credentials[0], credentials[1]));
|
||||
url = serviceUrl.replace(credentials[0] + ":" + credentials[1] + "@",
|
||||
"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,29 +101,52 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
return builder.baseUrl(url);
|
||||
}
|
||||
|
||||
private static BeanSerializerModifier createJsonSerializerModifier() {
|
||||
return new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config, BeanDescription beanDesc,
|
||||
JsonSerializer<?> serializer) {
|
||||
if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
|
||||
return new InstanceInfoJsonBeanSerializer((BeanSerializerBase) serializer, false);
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void setCodecs(WebClient.Builder builder) {
|
||||
ObjectMapper objectMapper = objectMapper();
|
||||
builder.codecs(configurer -> {
|
||||
ClientCodecConfigurer.ClientDefaultCodecs defaults = configurer.defaultCodecs();
|
||||
defaults.jackson2JsonEncoder(new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
defaults.jackson2JsonDecoder(new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
ClientCodecConfigurer.ClientDefaultCodecs defaults = configurer
|
||||
.defaultCodecs();
|
||||
defaults.jackson2JsonEncoder(
|
||||
new Jackson2JsonEncoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
defaults.jackson2JsonDecoder(
|
||||
new Jackson2JsonDecoder(objectMapper, MediaType.APPLICATION_JSON));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// Skip over 4xx http errors
|
||||
private ExchangeFilterFunction http4XxErrorExchangeFilterFunction() {
|
||||
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
|
||||
// literally 400 pass the tests, not 4xxClientError
|
||||
if (clientResponse.statusCode().value() == 400) {
|
||||
ClientResponse newResponse = ClientResponse.from(clientResponse)
|
||||
.statusCode(HttpStatus.OK).build();
|
||||
newResponse.body(
|
||||
(clientHttpResponse, context) -> clientHttpResponse.getBody());
|
||||
return Mono.just(newResponse);
|
||||
}
|
||||
return Mono.just(clientResponse);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the serialization configurations required by the Eureka Server. JSON
|
||||
* content exchanged with eureka requires a root node matching the entity being
|
||||
* serialized or deserialized. Achieved with
|
||||
* {@link SerializationFeature#WRAP_ROOT_VALUE} and
|
||||
* {@link DeserializationFeature#UNWRAP_ROOT_VALUE}.
|
||||
* {@link PropertyNamingStrategy.SnakeCaseStrategy} is applied to the underlying
|
||||
* {@link ObjectMapper}.
|
||||
* @deprecated to be removed.
|
||||
* @return a {@link MappingJackson2HttpMessageConverter} object
|
||||
*/
|
||||
@Deprecated
|
||||
public MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter() {
|
||||
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
converter.setObjectMapper(objectMapper());
|
||||
return converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the serialization configurations required by the Eureka Server. JSON
|
||||
* content exchanged with eureka requires a root node matching the entity being
|
||||
@@ -142,17 +173,19 @@ public class WebClientTransportClientFactory implements TransportClientFactory {
|
||||
return objectMapper;
|
||||
}
|
||||
|
||||
// Skip over 4xx http errors
|
||||
private ExchangeFilterFunction http4XxErrorExchangeFilterFunction() {
|
||||
return ExchangeFilterFunction.ofResponseProcessor(clientResponse -> {
|
||||
// literally 400 pass the tests, not 4xxClientError
|
||||
if (clientResponse.statusCode().value() == 400) {
|
||||
ClientResponse newResponse = ClientResponse.from(clientResponse).statusCode(HttpStatus.OK).build();
|
||||
newResponse.body((clientHttpResponse, context) -> clientHttpResponse.getBody());
|
||||
return Mono.just(newResponse);
|
||||
@Deprecated // reduce visibility in future release
|
||||
public static BeanSerializerModifier createJsonSerializerModifier() {
|
||||
return new BeanSerializerModifier() {
|
||||
@Override
|
||||
public JsonSerializer<?> modifySerializer(SerializationConfig config,
|
||||
BeanDescription beanDesc, JsonSerializer<?> serializer) {
|
||||
if (beanDesc.getBeanClass().isAssignableFrom(InstanceInfo.class)) {
|
||||
return new InstanceInfoJsonBeanSerializer(
|
||||
(BeanSerializerBase) serializer, false);
|
||||
}
|
||||
return serializer;
|
||||
}
|
||||
return Mono.just(clientResponse);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+14
-8
@@ -26,7 +26,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.cloud.loadbalancer.config.LoadBalancerZoneConfig;
|
||||
import org.springframework.cloud.netflix.eureka.support.ZoneUtils;
|
||||
import org.springframework.cloud.netflix.ribbon.eureka.ZoneUtils;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -45,7 +45,8 @@ import static org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancer
|
||||
@ConditionalOnBean({ LoadBalancerZoneConfig.class, EurekaLoadBalancerProperties.class })
|
||||
public class EurekaLoadBalancerClientConfiguration {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(EurekaLoadBalancerClientConfiguration.class);
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(EurekaLoadBalancerClientConfiguration.class);
|
||||
|
||||
private final EurekaClientConfig clientConfig;
|
||||
|
||||
@@ -55,8 +56,10 @@ public class EurekaLoadBalancerClientConfiguration {
|
||||
|
||||
private final EurekaLoadBalancerProperties eurekaLoadBalancerProperties;
|
||||
|
||||
public EurekaLoadBalancerClientConfiguration(@Autowired(required = false) EurekaClientConfig clientConfig,
|
||||
@Autowired(required = false) EurekaInstanceConfig eurekaInstanceConfig, LoadBalancerZoneConfig zoneConfig,
|
||||
public EurekaLoadBalancerClientConfiguration(
|
||||
@Autowired(required = false) EurekaClientConfig clientConfig,
|
||||
@Autowired(required = false) EurekaInstanceConfig eurekaInstanceConfig,
|
||||
LoadBalancerZoneConfig zoneConfig,
|
||||
EurekaLoadBalancerProperties eurekaLoadBalancerProperties) {
|
||||
this.clientConfig = clientConfig;
|
||||
this.eurekaConfig = eurekaInstanceConfig;
|
||||
@@ -80,14 +83,17 @@ public class EurekaLoadBalancerClientConfiguration {
|
||||
|
||||
private String getZoneFromEureka() {
|
||||
String zone;
|
||||
boolean approximateZoneFromHostname = eurekaLoadBalancerProperties.isApproximateZoneFromHostname();
|
||||
boolean approximateZoneFromHostname = eurekaLoadBalancerProperties
|
||||
.isApproximateZoneFromHostname();
|
||||
if (approximateZoneFromHostname && eurekaConfig != null) {
|
||||
return ZoneUtils.extractApproximateZone(this.eurekaConfig.getHostName(false));
|
||||
}
|
||||
else {
|
||||
zone = eurekaConfig == null ? null : eurekaConfig.getMetadataMap().get("zone");
|
||||
if (StringUtils.isEmpty(zone) && clientConfig != null) {
|
||||
String[] zones = clientConfig.getAvailabilityZones(clientConfig.getRegion());
|
||||
zone = eurekaConfig == null ? null
|
||||
: eurekaConfig.getMetadataMap().get("zone");
|
||||
if (StringUtils.isEmpty(zone)) {
|
||||
String[] zones = clientConfig
|
||||
.getAvailabilityZones(clientConfig.getRegion());
|
||||
// Pick the first one from the regions we want to connect to
|
||||
zone = zones != null && zones.length > 0 ? zones[0] : null;
|
||||
}
|
||||
|
||||
+42
-31
@@ -34,27 +34,29 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv
|
||||
|
||||
private static final int RANDOM_PORT = 0;
|
||||
|
||||
private static final Log log = LogFactory.getLog(DefaultManagementMetadataProvider.class);
|
||||
private static final Log log = LogFactory
|
||||
.getLog(DefaultManagementMetadataProvider.class);
|
||||
|
||||
@Override
|
||||
public ManagementMetadata get(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
|
||||
String managementContextPath, Integer managementPort) {
|
||||
public ManagementMetadata get(EurekaInstanceConfigBean instance, int serverPort,
|
||||
String serverContextPath, String managementContextPath,
|
||||
Integer managementPort) {
|
||||
if (isRandom(managementPort)) {
|
||||
return null;
|
||||
}
|
||||
if (managementPort == null && isRandom(serverPort)) {
|
||||
return null;
|
||||
}
|
||||
String healthCheckUrl = getHealthCheckUrl(instance, serverPort, serverContextPath, managementContextPath,
|
||||
managementPort, false);
|
||||
String statusPageUrl = getStatusPageUrl(instance, serverPort, serverContextPath, managementContextPath,
|
||||
managementPort);
|
||||
String healthCheckUrl = getHealthCheckUrl(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort, false);
|
||||
String statusPageUrl = getStatusPageUrl(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort);
|
||||
|
||||
ManagementMetadata metadata = new ManagementMetadata(healthCheckUrl, statusPageUrl,
|
||||
managementPort == null ? serverPort : managementPort);
|
||||
ManagementMetadata metadata = new ManagementMetadata(healthCheckUrl,
|
||||
statusPageUrl, managementPort == null ? serverPort : managementPort);
|
||||
if (instance.isSecurePortEnabled()) {
|
||||
metadata.setSecureHealthCheckUrl(getHealthCheckUrl(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort, true));
|
||||
metadata.setSecureHealthCheckUrl(getHealthCheckUrl(instance, serverPort,
|
||||
serverContextPath, managementContextPath, managementPort, true));
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
@@ -63,36 +65,41 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv
|
||||
return port != null && port == RANDOM_PORT;
|
||||
}
|
||||
|
||||
protected String getHealthCheckUrl(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
|
||||
String managementContextPath, Integer managementPort, boolean isSecure) {
|
||||
protected String getHealthCheckUrl(EurekaInstanceConfigBean instance, int serverPort,
|
||||
String serverContextPath, String managementContextPath,
|
||||
Integer managementPort, boolean isSecure) {
|
||||
String healthCheckUrlPath = instance.getHealthCheckUrlPath();
|
||||
String healthCheckUrl = getUrl(instance, serverPort, serverContextPath, managementContextPath, managementPort,
|
||||
healthCheckUrlPath, isSecure);
|
||||
String healthCheckUrl = getUrl(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort, healthCheckUrlPath, isSecure);
|
||||
log.debug("Constructed eureka meta-data healthcheckUrl: " + healthCheckUrl);
|
||||
return healthCheckUrl;
|
||||
}
|
||||
|
||||
public String getStatusPageUrl(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
|
||||
String managementContextPath, Integer managementPort) {
|
||||
public String getStatusPageUrl(EurekaInstanceConfigBean instance, int serverPort,
|
||||
String serverContextPath, String managementContextPath,
|
||||
Integer managementPort) {
|
||||
String statusPageUrlPath = instance.getStatusPageUrlPath();
|
||||
String statusPageUrl = getUrl(instance, serverPort, serverContextPath, managementContextPath, managementPort,
|
||||
statusPageUrlPath, false);
|
||||
String statusPageUrl = getUrl(instance, serverPort, serverContextPath,
|
||||
managementContextPath, managementPort, statusPageUrlPath, false);
|
||||
log.debug("Constructed eureka meta-data statusPageUrl: " + statusPageUrl);
|
||||
return statusPageUrl;
|
||||
}
|
||||
|
||||
private String getUrl(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
|
||||
String managementContextPath, Integer managementPort, String urlPath, boolean isSecure) {
|
||||
managementContextPath = refineManagementContextPath(serverContextPath, managementContextPath, managementPort);
|
||||
private String getUrl(EurekaInstanceConfigBean instance, int serverPort,
|
||||
String serverContextPath, String managementContextPath,
|
||||
Integer managementPort, String urlPath, boolean isSecure) {
|
||||
managementContextPath = refineManagementContextPath(serverContextPath,
|
||||
managementContextPath, managementPort);
|
||||
if (managementPort == null) {
|
||||
managementPort = serverPort;
|
||||
}
|
||||
String scheme = isSecure ? "https" : "http";
|
||||
return constructValidUrl(scheme, instance.getHostname(), managementPort, managementContextPath, urlPath);
|
||||
return constructValidUrl(scheme, instance.getHostname(), managementPort,
|
||||
managementContextPath, urlPath);
|
||||
}
|
||||
|
||||
private String refineManagementContextPath(String serverContextPath, String managementContextPath,
|
||||
Integer managementPort) {
|
||||
private String refineManagementContextPath(String serverContextPath,
|
||||
String managementContextPath, Integer managementPort) {
|
||||
// management context path is relative to server context path when no management
|
||||
// port is set
|
||||
if (managementContextPath != null && managementPort == null) {
|
||||
@@ -107,18 +114,21 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv
|
||||
return serverContextPath;
|
||||
}
|
||||
|
||||
private String constructValidUrl(String scheme, String hostname, int port, String contextPath, String statusPath) {
|
||||
private String constructValidUrl(String scheme, String hostname, int port,
|
||||
String contextPath, String statusPath) {
|
||||
try {
|
||||
if (!contextPath.endsWith("/")) {
|
||||
contextPath = contextPath + "/";
|
||||
}
|
||||
String refinedContextPath = '/' + StringUtils.trimLeadingCharacter(contextPath, '/');
|
||||
String refinedContextPath = '/'
|
||||
+ StringUtils.trimLeadingCharacter(contextPath, '/');
|
||||
URL base = new URL(scheme, hostname, port, refinedContextPath);
|
||||
String refinedStatusPath = refinedStatusPath(statusPath, contextPath);
|
||||
return new URL(base, refinedStatusPath).toString();
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
String message = getErrorMessage(scheme, hostname, port, contextPath, statusPath);
|
||||
String message = getErrorMessage(scheme, hostname, port, contextPath,
|
||||
statusPath);
|
||||
throw new IllegalStateException(message, e);
|
||||
}
|
||||
}
|
||||
@@ -130,10 +140,11 @@ public class DefaultManagementMetadataProvider implements ManagementMetadataProv
|
||||
return StringUtils.trimLeadingCharacter(statusPath, '/');
|
||||
}
|
||||
|
||||
private String getErrorMessage(String scheme, String hostname, int port, String contextPath, String statusPath) {
|
||||
private String getErrorMessage(String scheme, String hostname, int port,
|
||||
String contextPath, String statusPath) {
|
||||
return String.format(
|
||||
"Failed to construct url for scheme: %s, hostName: %s port: %s contextPath: %s statusPath: %s", scheme,
|
||||
hostname, port, contextPath, statusPath);
|
||||
"Failed to construct url for scheme: %s, hostName: %s port: %s contextPath: %s statusPath: %s",
|
||||
scheme, hostname, port, contextPath, statusPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-2
@@ -34,7 +34,8 @@ public class ManagementMetadata {
|
||||
|
||||
private String secureHealthCheckUrl;
|
||||
|
||||
public ManagementMetadata(String healthCheckUrl, String statusPageUrl, Integer managementPort) {
|
||||
public ManagementMetadata(String healthCheckUrl, String statusPageUrl,
|
||||
Integer managementPort) {
|
||||
this.healthCheckUrl = healthCheckUrl;
|
||||
this.statusPageUrl = statusPageUrl;
|
||||
this.managementPort = managementPort;
|
||||
@@ -70,7 +71,8 @@ public class ManagementMetadata {
|
||||
return false;
|
||||
}
|
||||
ManagementMetadata that = (ManagementMetadata) o;
|
||||
return Objects.equals(healthCheckUrl, that.healthCheckUrl) && Objects.equals(statusPageUrl, that.statusPageUrl)
|
||||
return Objects.equals(healthCheckUrl, that.healthCheckUrl)
|
||||
&& Objects.equals(statusPageUrl, that.statusPageUrl)
|
||||
&& Objects.equals(managementPort, that.managementPort);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -25,7 +25,8 @@ import org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean;
|
||||
*/
|
||||
public interface ManagementMetadataProvider {
|
||||
|
||||
ManagementMetadata get(EurekaInstanceConfigBean instance, int serverPort, String serverContextPath,
|
||||
String managementContextPath, Integer managementPort);
|
||||
ManagementMetadata get(EurekaInstanceConfigBean instance, int serverPort,
|
||||
String serverContextPath, String managementContextPath,
|
||||
Integer managementPort);
|
||||
|
||||
}
|
||||
|
||||
+7
-4
@@ -39,7 +39,8 @@ public class EurekaReactiveDiscoveryClient implements ReactiveDiscoveryClient {
|
||||
|
||||
private final EurekaClientConfig clientConfig;
|
||||
|
||||
public EurekaReactiveDiscoveryClient(EurekaClient eurekaClient, EurekaClientConfig clientConfig) {
|
||||
public EurekaReactiveDiscoveryClient(EurekaClient eurekaClient,
|
||||
EurekaClientConfig clientConfig) {
|
||||
this.eurekaClient = eurekaClient;
|
||||
this.clientConfig = clientConfig;
|
||||
}
|
||||
@@ -51,7 +52,9 @@ public class EurekaReactiveDiscoveryClient implements ReactiveDiscoveryClient {
|
||||
|
||||
@Override
|
||||
public Flux<ServiceInstance> getInstances(String serviceId) {
|
||||
return Flux.defer(() -> Flux.fromIterable(eurekaClient.getInstancesByVipAddress(serviceId, false)))
|
||||
return Flux
|
||||
.defer(() -> Flux.fromIterable(
|
||||
eurekaClient.getInstancesByVipAddress(serviceId, false)))
|
||||
.map(EurekaServiceInstance::new);
|
||||
}
|
||||
|
||||
@@ -59,8 +62,8 @@ public class EurekaReactiveDiscoveryClient implements ReactiveDiscoveryClient {
|
||||
public Flux<String> getServices() {
|
||||
return Flux.defer(() -> Mono.justOrEmpty(eurekaClient.getApplications()))
|
||||
.flatMapIterable(Applications::getRegisteredApplications)
|
||||
.filter(application -> !application.getInstances().isEmpty()).map(Application::getName)
|
||||
.map(String::toLowerCase);
|
||||
.filter(application -> !application.getInstances().isEmpty())
|
||||
.map(Application::getName).map(String::toLowerCase);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-5
@@ -48,23 +48,26 @@ import org.springframework.context.annotation.Configuration;
|
||||
@ConditionalOnReactiveDiscoveryEnabled
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
|
||||
@EnableConfigurationProperties
|
||||
@AutoConfigureAfter({ EurekaClientAutoConfiguration.class, ReactiveCompositeDiscoveryClientAutoConfiguration.class })
|
||||
@AutoConfigureAfter({ EurekaClientAutoConfiguration.class,
|
||||
ReactiveCompositeDiscoveryClientAutoConfiguration.class })
|
||||
@AutoConfigureBefore(ReactiveCommonsClientAutoConfiguration.class)
|
||||
@ImportAutoConfiguration(EurekaClientAutoConfiguration.class)
|
||||
public class EurekaReactiveDiscoveryClientConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EurekaReactiveDiscoveryClient eurekaReactiveDiscoveryClient(EurekaClient client,
|
||||
EurekaClientConfig clientConfig) {
|
||||
public EurekaReactiveDiscoveryClient eurekaReactiveDiscoveryClient(
|
||||
EurekaClient client, EurekaClientConfig clientConfig) {
|
||||
return new EurekaReactiveDiscoveryClient(client, clientConfig);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
|
||||
@ConditionalOnClass(
|
||||
name = "org.springframework.boot.actuate.health.ReactiveHealthIndicator")
|
||||
@ConditionalOnDiscoveryHealthIndicatorEnabled
|
||||
public ReactiveDiscoveryClientHealthIndicator eurekaReactiveDiscoveryClientHealthIndicator(
|
||||
EurekaReactiveDiscoveryClient client, DiscoveryClientHealthIndicatorProperties properties) {
|
||||
EurekaReactiveDiscoveryClient client,
|
||||
DiscoveryClientHealthIndicatorProperties properties) {
|
||||
return new ReactiveDiscoveryClientHealthIndicator(client, properties);
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -39,8 +39,8 @@ import org.springframework.core.Ordered;
|
||||
* @author Jakub Narloch
|
||||
* @author Raiyan Raiyan
|
||||
*/
|
||||
public class EurekaAutoServiceRegistration
|
||||
implements AutoServiceRegistration, SmartLifecycle, Ordered, SmartApplicationListener {
|
||||
public class EurekaAutoServiceRegistration implements AutoServiceRegistration,
|
||||
SmartLifecycle, Ordered, SmartApplicationListener {
|
||||
|
||||
private static final Log log = LogFactory.getLog(EurekaAutoServiceRegistration.class);
|
||||
|
||||
@@ -56,8 +56,8 @@ public class EurekaAutoServiceRegistration
|
||||
|
||||
private EurekaRegistration registration;
|
||||
|
||||
public EurekaAutoServiceRegistration(ApplicationContext context, EurekaServiceRegistry serviceRegistry,
|
||||
EurekaRegistration registration) {
|
||||
public EurekaAutoServiceRegistration(ApplicationContext context,
|
||||
EurekaServiceRegistry serviceRegistry, EurekaRegistration registration) {
|
||||
this.context = context;
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
this.registration = registration;
|
||||
@@ -82,7 +82,8 @@ public class EurekaAutoServiceRegistration
|
||||
|
||||
this.serviceRegistry.register(this.registration);
|
||||
|
||||
this.context.publishEvent(new InstanceRegisteredEvent<>(this, this.registration.getInstanceConfig()));
|
||||
this.context.publishEvent(new InstanceRegisteredEvent<>(this,
|
||||
this.registration.getInstanceConfig()));
|
||||
this.running.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
+21
-12
@@ -59,8 +59,9 @@ public class EurekaRegistration implements Registration {
|
||||
|
||||
private ObjectProvider<HealthCheckHandler> healthCheckHandler;
|
||||
|
||||
private EurekaRegistration(CloudEurekaInstanceConfig instanceConfig, EurekaClient eurekaClient,
|
||||
ApplicationInfoManager applicationInfoManager, ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
private EurekaRegistration(CloudEurekaInstanceConfig instanceConfig,
|
||||
EurekaClient eurekaClient, ApplicationInfoManager applicationInfoManager,
|
||||
ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
this.eurekaClient = eurekaClient;
|
||||
this.instanceConfig = instanceConfig;
|
||||
this.applicationInfoManager = applicationInfoManager;
|
||||
@@ -112,7 +113,8 @@ public class EurekaRegistration implements Registration {
|
||||
public CloudEurekaClient getEurekaClient() {
|
||||
if (this.cloudEurekaClient.get() == null) {
|
||||
try {
|
||||
this.cloudEurekaClient.compareAndSet(null, getTargetObject(eurekaClient, CloudEurekaClient.class));
|
||||
this.cloudEurekaClient.compareAndSet(null,
|
||||
getTargetObject(eurekaClient, CloudEurekaClient.class));
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("error getting CloudEurekaClient", e);
|
||||
@@ -144,7 +146,8 @@ public class EurekaRegistration implements Registration {
|
||||
return healthCheckHandler;
|
||||
}
|
||||
|
||||
public void setHealthCheckHandler(ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
public void setHealthCheckHandler(
|
||||
ObjectProvider<HealthCheckHandler> healthCheckHandler) {
|
||||
this.healthCheckHandler = healthCheckHandler;
|
||||
}
|
||||
|
||||
@@ -200,7 +203,8 @@ public class EurekaRegistration implements Registration {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder with(EurekaClientConfig clientConfig, ApplicationEventPublisher publisher) {
|
||||
public Builder with(EurekaClientConfig clientConfig,
|
||||
ApplicationEventPublisher publisher) {
|
||||
this.clientConfig = clientConfig;
|
||||
this.publisher = publisher;
|
||||
return this;
|
||||
@@ -210,17 +214,22 @@ public class EurekaRegistration implements Registration {
|
||||
Assert.notNull(instanceConfig, "instanceConfig may not be null");
|
||||
|
||||
if (this.applicationInfoManager == null) {
|
||||
InstanceInfo instanceInfo = new InstanceInfoFactory().create(this.instanceConfig);
|
||||
this.applicationInfoManager = new ApplicationInfoManager(this.instanceConfig, instanceInfo);
|
||||
InstanceInfo instanceInfo = new InstanceInfoFactory()
|
||||
.create(this.instanceConfig);
|
||||
this.applicationInfoManager = new ApplicationInfoManager(
|
||||
this.instanceConfig, instanceInfo);
|
||||
}
|
||||
if (this.eurekaClient == null) {
|
||||
Assert.notNull(this.clientConfig, "if eurekaClient is null, EurekaClientConfig may not be null");
|
||||
Assert.notNull(this.publisher, "if eurekaClient is null, ApplicationEventPublisher may not be null");
|
||||
Assert.notNull(this.clientConfig,
|
||||
"if eurekaClient is null, EurekaClientConfig may not be null");
|
||||
Assert.notNull(this.publisher,
|
||||
"if eurekaClient is null, ApplicationEventPublisher may not be null");
|
||||
|
||||
this.eurekaClient = new CloudEurekaClient(this.applicationInfoManager, this.clientConfig,
|
||||
this.publisher);
|
||||
this.eurekaClient = new CloudEurekaClient(this.applicationInfoManager,
|
||||
this.clientConfig, this.publisher);
|
||||
}
|
||||
return new EurekaRegistration(instanceConfig, eurekaClient, applicationInfoManager, healthCheckHandler);
|
||||
return new EurekaRegistration(instanceConfig, eurekaClient,
|
||||
applicationInfoManager, healthCheckHandler);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+16
-9
@@ -38,14 +38,17 @@ public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration
|
||||
maybeInitializeClient(reg);
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Registering application " + reg.getApplicationInfoManager().getInfo().getAppName()
|
||||
+ " with eureka with status " + reg.getInstanceConfig().getInitialStatus());
|
||||
log.info("Registering application "
|
||||
+ reg.getApplicationInfoManager().getInfo().getAppName()
|
||||
+ " with eureka with status "
|
||||
+ reg.getInstanceConfig().getInitialStatus());
|
||||
}
|
||||
|
||||
reg.getApplicationInfoManager().setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
|
||||
reg.getApplicationInfoManager()
|
||||
.setInstanceStatus(reg.getInstanceConfig().getInitialStatus());
|
||||
|
||||
reg.getHealthCheckHandler()
|
||||
.ifAvailable(healthCheckHandler -> reg.getEurekaClient().registerHealthCheck(healthCheckHandler));
|
||||
reg.getHealthCheckHandler().ifAvailable(healthCheckHandler -> reg
|
||||
.getEurekaClient().registerHealthCheck(healthCheckHandler));
|
||||
}
|
||||
|
||||
private void maybeInitializeClient(EurekaRegistration reg) {
|
||||
@@ -59,11 +62,13 @@ public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration
|
||||
if (reg.getApplicationInfoManager().getInfo() != null) {
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
log.info("Unregistering application " + reg.getApplicationInfoManager().getInfo().getAppName()
|
||||
log.info("Unregistering application "
|
||||
+ reg.getApplicationInfoManager().getInfo().getAppName()
|
||||
+ " with eureka with status DOWN");
|
||||
}
|
||||
|
||||
reg.getApplicationInfoManager().setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);
|
||||
reg.getApplicationInfoManager()
|
||||
.setInstanceStatus(InstanceInfo.InstanceStatus.DOWN);
|
||||
|
||||
// shutdown of eureka client should happen with EurekaRegistration.close()
|
||||
// auto registration will create a bean which will be properly disposed
|
||||
@@ -82,7 +87,8 @@ public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration
|
||||
}
|
||||
|
||||
// TODO: howto deal with status types across discovery systems?
|
||||
InstanceInfo.InstanceStatus newStatus = InstanceInfo.InstanceStatus.toEnum(status);
|
||||
InstanceInfo.InstanceStatus newStatus = InstanceInfo.InstanceStatus
|
||||
.toEnum(status);
|
||||
registration.getEurekaClient().setStatus(newStatus, info);
|
||||
}
|
||||
|
||||
@@ -90,7 +96,8 @@ public class EurekaServiceRegistry implements ServiceRegistry<EurekaRegistration
|
||||
public Object getStatus(EurekaRegistration registration) {
|
||||
String appname = registration.getApplicationInfoManager().getInfo().getAppName();
|
||||
String instanceId = registration.getApplicationInfoManager().getInfo().getId();
|
||||
InstanceInfo info = registration.getEurekaClient().getInstanceInfo(appname, instanceId);
|
||||
InstanceInfo info = registration.getEurekaClient().getInstanceInfo(appname,
|
||||
instanceId);
|
||||
|
||||
HashMap<String, Object> status = new HashMap<>();
|
||||
if (info != null) {
|
||||
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.AllNestedConditions;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
|
||||
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
|
||||
/**
|
||||
* Conditional that requires both Ribbon and Eureka to be enabled.
|
||||
* @author Ihor Kryvenko
|
||||
* @author Spencer Gibb
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@Target({ ElementType.TYPE, ElementType.METHOD })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Conditional(ConditionalOnRibbonAndEurekaEnabled.OnRibbonAndEurekaEnabledCondition.class)
|
||||
public @interface ConditionalOnRibbonAndEurekaEnabled {
|
||||
|
||||
class OnRibbonAndEurekaEnabledCondition extends AllNestedConditions {
|
||||
|
||||
OnRibbonAndEurekaEnabledCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnClass(DiscoveryEnabledNIWSServerList.class)
|
||||
@ConditionalOnBean(SpringClientFactory.class)
|
||||
@ConditionalOnProperty(value = "ribbon.eureka.enabled", matchIfMissing = true)
|
||||
static class Defaults {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnBean(EurekaClient.class)
|
||||
static class EurekaBeans {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "eureka.client.enabled", matchIfMissing = true)
|
||||
@ConditionalOnDiscoveryEnabled
|
||||
static class OnEurekaClientEnabled {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonProperties;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class DomainExtractingServerList implements ServerList<DiscoveryEnabledServer> {
|
||||
|
||||
private ServerList<DiscoveryEnabledServer> list;
|
||||
|
||||
private final RibbonProperties ribbon;
|
||||
|
||||
private boolean approximateZoneFromHostname;
|
||||
|
||||
public DomainExtractingServerList(ServerList<DiscoveryEnabledServer> list,
|
||||
IClientConfig clientConfig, boolean approximateZoneFromHostname) {
|
||||
this.list = list;
|
||||
this.ribbon = RibbonProperties.from(clientConfig);
|
||||
this.approximateZoneFromHostname = approximateZoneFromHostname;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DiscoveryEnabledServer> getInitialListOfServers() {
|
||||
List<DiscoveryEnabledServer> servers = setZones(
|
||||
this.list.getInitialListOfServers());
|
||||
return servers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DiscoveryEnabledServer> getUpdatedListOfServers() {
|
||||
List<DiscoveryEnabledServer> servers = setZones(
|
||||
this.list.getUpdatedListOfServers());
|
||||
return servers;
|
||||
}
|
||||
|
||||
private List<DiscoveryEnabledServer> setZones(List<DiscoveryEnabledServer> servers) {
|
||||
List<DiscoveryEnabledServer> result = new ArrayList<>();
|
||||
boolean isSecure = this.ribbon.isSecure(true);
|
||||
boolean shouldUseIpAddr = this.ribbon.isUseIPAddrForServer();
|
||||
for (DiscoveryEnabledServer server : servers) {
|
||||
result.add(new DomainExtractingServer(server, isSecure, shouldUseIpAddr,
|
||||
this.approximateZoneFromHostname));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class DomainExtractingServer extends DiscoveryEnabledServer {
|
||||
|
||||
private String id;
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
DomainExtractingServer(DiscoveryEnabledServer server, boolean useSecurePort,
|
||||
boolean useIpAddr, boolean approximateZoneFromHostname) {
|
||||
// host and port are set in super()
|
||||
super(server.getInstanceInfo(), useSecurePort, useIpAddr);
|
||||
if (server.getInstanceInfo().getMetadata().containsKey("zone")) {
|
||||
setZone(server.getInstanceInfo().getMetadata().get("zone"));
|
||||
}
|
||||
else if (approximateZoneFromHostname) {
|
||||
setZone(ZoneUtils.extractApproximateZone(server.getHost()));
|
||||
}
|
||||
else {
|
||||
setZone(server.getZone());
|
||||
}
|
||||
setId(extractId(server));
|
||||
setAlive(server.isAlive());
|
||||
setReadyToServe(server.isReadyToServe());
|
||||
}
|
||||
|
||||
private String extractId(Server server) {
|
||||
if (server instanceof DiscoveryEnabledServer) {
|
||||
DiscoveryEnabledServer enabled = (DiscoveryEnabledServer) server;
|
||||
InstanceInfo instance = enabled.getInstanceInfo();
|
||||
if (instance.getMetadata().containsKey("instanceId")) {
|
||||
return instance.getHostName() + ":"
|
||||
+ instance.getMetadata().get("instanceId");
|
||||
}
|
||||
}
|
||||
return super.getId();
|
||||
}
|
||||
|
||||
}
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.inject.Provider;
|
||||
|
||||
import com.netflix.appinfo.EurekaInstanceConfig;
|
||||
import com.netflix.client.config.IClientConfig;
|
||||
import com.netflix.config.ConfigurationManager;
|
||||
import com.netflix.config.DeploymentContext.ContextKey;
|
||||
import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.loadbalancer.IPing;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList;
|
||||
import com.netflix.niws.loadbalancer.NIWSDiscoveryPing;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.cloud.netflix.ribbon.PropertiesFactory;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClientName;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonUtils;
|
||||
import org.springframework.cloud.netflix.ribbon.ServerIntrospector;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Preprocessor that configures defaults for eureka-discovered ribbon clients. Such as:
|
||||
* <code>@zone</code>, NIWSServerListClassName, DeploymentContextBasedVipAddresses,
|
||||
* NFLoadBalancerRuleClassName, NIWSServerListFilterClassName and more
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class EurekaRibbonClientConfiguration {
|
||||
|
||||
private static final Log log = LogFactory
|
||||
.getLog(EurekaRibbonClientConfiguration.class);
|
||||
|
||||
@Value("${ribbon.eureka.approximateZoneFromHostname:false}")
|
||||
private boolean approximateZoneFromHostname = false;
|
||||
|
||||
@RibbonClientName
|
||||
private String serviceId = "client";
|
||||
|
||||
@Autowired(required = false)
|
||||
private EurekaClientConfig clientConfig;
|
||||
|
||||
@Autowired(required = false)
|
||||
private EurekaInstanceConfig eurekaConfig;
|
||||
|
||||
@Autowired
|
||||
private PropertiesFactory propertiesFactory;
|
||||
|
||||
public EurekaRibbonClientConfiguration() {
|
||||
}
|
||||
|
||||
public EurekaRibbonClientConfiguration(EurekaClientConfig clientConfig,
|
||||
String serviceId, EurekaInstanceConfig eurekaConfig,
|
||||
boolean approximateZoneFromHostname) {
|
||||
this.clientConfig = clientConfig;
|
||||
this.serviceId = serviceId;
|
||||
this.eurekaConfig = eurekaConfig;
|
||||
this.approximateZoneFromHostname = approximateZoneFromHostname;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public IPing ribbonPing(IClientConfig config) {
|
||||
if (this.propertiesFactory.isSet(IPing.class, serviceId)) {
|
||||
return this.propertiesFactory.get(IPing.class, config, serviceId);
|
||||
}
|
||||
NIWSDiscoveryPing ping = new NIWSDiscoveryPing();
|
||||
ping.initWithNiwsConfig(config);
|
||||
return ping;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ServerList<?> ribbonServerList(IClientConfig config,
|
||||
Provider<EurekaClient> eurekaClientProvider) {
|
||||
if (this.propertiesFactory.isSet(ServerList.class, serviceId)) {
|
||||
return this.propertiesFactory.get(ServerList.class, config, serviceId);
|
||||
}
|
||||
DiscoveryEnabledNIWSServerList discoveryServerList = new DiscoveryEnabledNIWSServerList(
|
||||
config, eurekaClientProvider);
|
||||
DomainExtractingServerList serverList = new DomainExtractingServerList(
|
||||
discoveryServerList, config, this.approximateZoneFromHostname);
|
||||
return serverList;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServerIntrospector serverIntrospector() {
|
||||
return new EurekaServerIntrospector();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void preprocess() {
|
||||
String zone = ConfigurationManager.getDeploymentContext()
|
||||
.getValue(ContextKey.zone);
|
||||
if (this.clientConfig != null && StringUtils.isEmpty(zone)) {
|
||||
if (this.approximateZoneFromHostname && this.eurekaConfig != null) {
|
||||
String approxZone = ZoneUtils
|
||||
.extractApproximateZone(this.eurekaConfig.getHostName(false));
|
||||
log.debug("Setting Zone To " + approxZone);
|
||||
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone,
|
||||
approxZone);
|
||||
}
|
||||
else {
|
||||
String availabilityZone = this.eurekaConfig == null ? null
|
||||
: this.eurekaConfig.getMetadataMap().get("zone");
|
||||
if (availabilityZone == null) {
|
||||
String[] zones = this.clientConfig
|
||||
.getAvailabilityZones(this.clientConfig.getRegion());
|
||||
// Pick the first one from the regions we want to connect to
|
||||
availabilityZone = zones != null && zones.length > 0 ? zones[0]
|
||||
: null;
|
||||
}
|
||||
if (availabilityZone != null) {
|
||||
// You can set this with archaius.deployment.* (maybe requires
|
||||
// custom deployment context)?
|
||||
ConfigurationManager.getDeploymentContext().setValue(ContextKey.zone,
|
||||
availabilityZone);
|
||||
}
|
||||
}
|
||||
}
|
||||
RibbonUtils.initializeRibbonDefaults(serviceId);
|
||||
}
|
||||
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.niws.loadbalancer.DiscoveryEnabledServer;
|
||||
|
||||
import org.springframework.cloud.netflix.ribbon.DefaultServerIntrospector;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class EurekaServerIntrospector extends DefaultServerIntrospector {
|
||||
|
||||
@Override
|
||||
public boolean isSecure(Server server) {
|
||||
if (server instanceof DiscoveryEnabledServer) {
|
||||
DiscoveryEnabledServer discoveryServer = (DiscoveryEnabledServer) server;
|
||||
return discoveryServer.getInstanceInfo()
|
||||
.isPortEnabled(InstanceInfo.PortType.SECURE);
|
||||
}
|
||||
return super.isSecure(server);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMetadata(Server server) {
|
||||
if (server instanceof DiscoveryEnabledServer) {
|
||||
DiscoveryEnabledServer discoveryServer = (DiscoveryEnabledServer) server;
|
||||
return discoveryServer.getInstanceInfo().getMetadata();
|
||||
}
|
||||
return super.getMetadata(server);
|
||||
}
|
||||
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2013-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonAutoConfiguration;
|
||||
import org.springframework.cloud.netflix.ribbon.RibbonClients;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Spring configuration for configuring Ribbon defaults to be Eureka based if Eureka
|
||||
* client is enabled.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Biju Kunjummen
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties
|
||||
@ConditionalOnRibbonAndEurekaEnabled
|
||||
@AutoConfigureAfter(RibbonAutoConfiguration.class)
|
||||
@RibbonClients(defaultConfiguration = EurekaRibbonClientConfiguration.class)
|
||||
public class RibbonEurekaAutoConfiguration {
|
||||
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.netflix.eureka.support;
|
||||
package org.springframework.cloud.netflix.ribbon.eureka;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -2,12 +2,10 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaClientConfigServerAutoConfiguration,\
|
||||
org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration,\
|
||||
org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration,\
|
||||
org.springframework.cloud.netflix.ribbon.eureka.RibbonEurekaAutoConfiguration,\
|
||||
org.springframework.cloud.netflix.eureka.EurekaDiscoveryClientConfiguration,\
|
||||
org.springframework.cloud.netflix.eureka.reactive.EurekaReactiveDiscoveryClientConfiguration,\
|
||||
org.springframework.cloud.netflix.eureka.loadbalancer.LoadBalancerEurekaAutoConfiguration
|
||||
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapConfiguration
|
||||
|
||||
org.springframework.boot.BootstrapRegistryInitializer=\
|
||||
org.springframework.cloud.netflix.eureka.config.EurekaConfigServerBootstrapper
|
||||
|
||||
+15
-10
@@ -16,7 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
@@ -32,29 +32,34 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Dave Syer
|
||||
* @author Biju Kunjummen
|
||||
*/
|
||||
class ConditionalOnRefreshScopeTests {
|
||||
public class ConditionalOnRefreshScopeTests {
|
||||
|
||||
@Test
|
||||
void refreshScopeIncluded() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class))
|
||||
public void refreshScopeIncluded() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class))
|
||||
.withUserConfiguration(Beans.class).run(c -> {
|
||||
assertThat(c).hasSingleBean(org.springframework.cloud.context.scope.refresh.RefreshScope.class);
|
||||
assertThat(c).hasSingleBean(
|
||||
org.springframework.cloud.context.scope.refresh.RefreshScope.class);
|
||||
assertThat(c.getBean("foo")).isEqualTo("foo");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshScopeIncludedAndPropertyDisabled() {
|
||||
new ApplicationContextRunner().withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class))
|
||||
.withPropertyValues("eureka.client.refresh.enable=false").withUserConfiguration(Beans.class).run(c -> {
|
||||
assertThat(c).hasSingleBean(org.springframework.cloud.context.scope.refresh.RefreshScope.class);
|
||||
public void refreshScopeIncludedAndPropertyDisabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(RefreshAutoConfiguration.class))
|
||||
.withPropertyValues("eureka.client.refresh.enable=false")
|
||||
.withUserConfiguration(Beans.class).run(c -> {
|
||||
assertThat(c).hasSingleBean(
|
||||
org.springframework.cloud.context.scope.refresh.RefreshScope.class);
|
||||
assertThat(c).doesNotHaveBean("foo");
|
||||
assertThat(c.getBean("bar")).isEqualTo("bar");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshScopeNotIncluded() {
|
||||
public void refreshScopeNotIncluded() {
|
||||
new ApplicationContextRunner().withUserConfiguration(Beans.class).run(c -> {
|
||||
assertThat(c).doesNotHaveBean("foo");
|
||||
assertThat(c.getBean("bar")).isEqualTo("bar");
|
||||
|
||||
+6
-3
@@ -18,27 +18,30 @@ package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import com.netflix.appinfo.ApplicationInfoManager;
|
||||
import com.netflix.appinfo.InstanceInfo;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
|
||||
class EurekaClientAutoConfigurationRandomPortTests {
|
||||
public class EurekaClientAutoConfigurationRandomPortTests {
|
||||
|
||||
@Autowired
|
||||
private ApplicationInfoManager infoManager;
|
||||
|
||||
@Test
|
||||
void instanceInfoPortShouldNotBeZero() {
|
||||
public void instanceInfoPortShouldNotBeZero() {
|
||||
InstanceInfo info = infoManager.getInfo();
|
||||
assertThat(info.getPort()).isGreaterThan(0);
|
||||
}
|
||||
|
||||
+229
-224
@@ -27,18 +27,16 @@ import com.netflix.discovery.EurekaClient;
|
||||
import com.netflix.discovery.EurekaClientConfig;
|
||||
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
|
||||
import com.sun.jersey.client.apache4.ApacheHttpClient4;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.context.event.ApplicationPreparedEvent;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
@@ -53,7 +51,6 @@ import org.springframework.cloud.context.scope.GenericScope;
|
||||
import org.springframework.cloud.netflix.eureka.config.DiscoveryClientOptionalArgsConfiguration;
|
||||
import org.springframework.cloud.netflix.eureka.serviceregistry.EurekaServiceRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -72,12 +69,12 @@ import static org.assertj.core.api.AssertionsForClassTypes.fail;
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Tim Ysewyn
|
||||
*/
|
||||
class EurekaClientAutoConfigurationTests {
|
||||
public class EurekaClientAutoConfigurationTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@AfterEach
|
||||
void after() {
|
||||
@After
|
||||
public void after() {
|
||||
if (this.context != null && this.context.isActive()) {
|
||||
this.context.close();
|
||||
}
|
||||
@@ -86,7 +83,8 @@ class EurekaClientAutoConfigurationTests {
|
||||
private void setupContext(Class<?>... config) {
|
||||
ConfigurationPropertySources.attach(this.context.getEnvironment());
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
DiscoveryClientOptionalArgsConfiguration.class, EurekaDiscoveryClientConfiguration.class);
|
||||
DiscoveryClientOptionalArgsConfiguration.class,
|
||||
EurekaDiscoveryClientConfiguration.class);
|
||||
for (Class<?> value : config) {
|
||||
this.context.register(value);
|
||||
}
|
||||
@@ -95,119 +93,141 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetManagementPortInMetadataMapIfEqualToServerPort() throws Exception {
|
||||
public void shouldSetManagementPortInMetadataMapIfEqualToServerPort()
|
||||
throws Exception {
|
||||
TestPropertyValues.of("server.port=8989").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
|
||||
assertThat(instance.getMetadataMap().get("management.port")).isEqualTo("8989");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotSetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=0").applyTo(this.context);
|
||||
public void shouldNotSetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=0")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
|
||||
assertThat(instance.getMetadataMap().get("management.port")).isEqualTo(null);
|
||||
assertThat(instance.getMetadataMap().get("jmx.port")).isEqualTo(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues.of("management.server.port=9999", "com.sun.management.jmxremote.port=6789")
|
||||
.applyTo(this.context);
|
||||
public void shouldSetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues.of("management.server.port=9999",
|
||||
"com.sun.management.jmxremote.port=6789").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getMetadataMap().get("management.port")).isEqualTo("9999");
|
||||
assertThat(instance.getMetadataMap().get("jmx.port")).isEqualTo("6789");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotResetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues.of("management.server.port=9999", "eureka.instance.metadata-map.jmx.port=9898",
|
||||
"eureka.instance.metadata-map.management.port=7878").applyTo(this.context);
|
||||
public void shouldNotResetManagementAndJmxPortsInMetadataMap() throws Exception {
|
||||
TestPropertyValues
|
||||
.of("management.server.port=9999",
|
||||
"eureka.instance.metadata-map.jmx.port=9898",
|
||||
"eureka.instance.metadata-map.management.port=7878")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getMetadataMap().get("management.port")).isEqualTo("7878");
|
||||
assertThat(instance.getMetadataMap().get("jmx.port")).isEqualTo("9898");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonSecurePortPeriods() {
|
||||
public void nonSecurePortPeriods() {
|
||||
testNonSecurePort("server.port");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonSecurePortUnderscores() {
|
||||
public void nonSecurePortUnderscores() {
|
||||
testNonSecurePortSystemProp("SERVER_PORT");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonSecurePort() {
|
||||
public void nonSecurePort() {
|
||||
testNonSecurePortSystemProp("PORT");
|
||||
assertThat(this.context.getBeanDefinition("eurekaClient").getFactoryMethodName()).isEqualTo("eurekaClient");
|
||||
assertThat(this.context.getBeanDefinition("eurekaClient").getFactoryMethodName())
|
||||
.isEqualTo("eurekaClient");
|
||||
}
|
||||
|
||||
@Test
|
||||
void securePortPeriods() {
|
||||
public void securePortPeriods() {
|
||||
testSecurePort("server.port");
|
||||
}
|
||||
|
||||
@Test
|
||||
void securePortUnderscores() {
|
||||
TestPropertyValues.of("eureka.instance.secure-port-enabled=true").applyTo(this.context);
|
||||
public void securePortUnderscores() {
|
||||
TestPropertyValues.of("eureka.instance.secure-port-enabled=true")
|
||||
.applyTo(this.context);
|
||||
addSystemEnvironment(this.context.getEnvironment(), "SERVER_PORT:8443");
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getSecurePort()).isEqualTo(8443);
|
||||
}
|
||||
|
||||
@Test
|
||||
void securePort() {
|
||||
public void securePort() {
|
||||
testSecurePort("PORT");
|
||||
assertThat(this.context.getBeanDefinition("eurekaClient").getFactoryMethodName()).isEqualTo("eurekaClient");
|
||||
assertThat(this.context.getBeanDefinition("eurekaClient").getFactoryMethodName())
|
||||
.isEqualTo("eurekaClient");
|
||||
}
|
||||
|
||||
@Test
|
||||
void managementPort() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999").applyTo(this.context);
|
||||
public void managementPort() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("9999")).as("Wrong status page: " + instance.getStatusPageUrl())
|
||||
.isTrue();
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("9999"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPort() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.statusPageUrlPath=/myStatusPage").applyTo(this.context);
|
||||
public void statusPageUrlPathAndManagementPort() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.statusPageUrlPath=/myStatusPage")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPort() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.healthCheckUrlPath=/myHealthCheck").applyTo(this.context);
|
||||
public void healthCheckUrlPathAndManagementPort() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.healthCheckUrlPath=/myHealthCheck")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().contains("/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrl_and_healthCheckUrl_do_not_contain_server_context_path() throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "server.contextPath=/service")
|
||||
.applyTo(this.context);
|
||||
public void statusPageUrl_and_healthCheckUrl_do_not_contain_server_context_path()
|
||||
throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"server.contextPath=/service").applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":9999/actuator/info"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":9999/actuator/health"))
|
||||
@@ -215,25 +235,34 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrl_and_healthCheckUrl_contain_management_context_path() throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.servlet.context-path=/management")
|
||||
public void statusPageUrl_and_healthCheckUrl_contain_management_context_path()
|
||||
throws Exception {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989",
|
||||
"management.server.servlet.context-path=/management")
|
||||
.applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":8989/management/actuator/info"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":8989/management/actuator/health"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
assertThat(
|
||||
instance.getHealthCheckUrl().endsWith(":8989/management/actuator/health"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl())
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrl_and_healthCheckUrl_contain_management_context_path_random_port() throws Exception {
|
||||
TestPropertyValues.of("server.port=0", "management.server.servlet.context-path=/management")
|
||||
public void statusPageUrl_and_healthCheckUrl_contain_management_context_path_random_port()
|
||||
throws Exception {
|
||||
TestPropertyValues
|
||||
.of("server.port=0", "management.server.servlet.context-path=/management")
|
||||
.applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrlPath().equals("/management/actuator/info"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrlPath()).isTrue();
|
||||
assertThat(instance.getHealthCheckUrlPath().equals("/management/actuator/health"))
|
||||
@@ -241,144 +270,97 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortAndContextPath() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage", "eureka.instance.status-page-url-path=/myStatusPage")
|
||||
public void statusPageUrlPathAndManagementPortAndContextPath() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortAndContextPath() {
|
||||
public void healthCheckUrlPathAndManagementPortAndContextPath() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999", "management.server.servlet.context-path=/manage",
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortAndContextPathKebobCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage", "eureka.instance.status-page-url-path=/myStatusPage")
|
||||
public void statusPageUrlPathAndManagementPortAndContextPathKebobCase() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortAndContextPathKebobCase() {
|
||||
public void healthCheckUrlPathAndManagementPortAndContextPathKebobCase() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999", "management.server.servlet.context-path=/manage",
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"management.server.servlet.context-path=/manage",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrl_and_healthCheckUrl_contain_management_base_path() throws Exception {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.base-path=/management").applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":8989/management/actuator/info"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":8989/management/actuator/health"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrl_and_healthCheckUrl_contain_management_base_path_random_port() throws Exception {
|
||||
TestPropertyValues.of("server.port=0", "management.server.base-path=/management").applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrlPath().equals("/management/actuator/info"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrlPath()).isTrue();
|
||||
assertThat(instance.getHealthCheckUrlPath().equals("/management/actuator/health"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrlPath()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortAndBasePath() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "management.server.base-path=/manage",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortAndBasePath() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "management.server.base-path=/manage",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortAndBasePathKebobCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "management.server.base-path=/manage",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().endsWith(":9999/manage/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortAndBasePathKebobCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "management.server.base-path=/manage",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().endsWith(":9999/manage/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathWithServerPortAndContextPathKebobCase() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "server.servlet.context-path=/servletContextPath",
|
||||
"eureka.instance.health-check-url-path=${server.servlet.context-path:}/myHealthCheck")
|
||||
public void healthCheckUrlPathWithServerPortAndContextPathKebobCase() {
|
||||
TestPropertyValues.of("server.port=8989",
|
||||
"server.servlet.context-path=/servletContextPath",
|
||||
"eureka.instance.health-check-url-path=${server.servlet.context-path:}/myHealthCheck")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl()).as("Wrong health check: " + instance.getHealthCheckUrl())
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl())
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl())
|
||||
.endsWith(":8989/servletContextPath/myHealthCheck");
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortKabobCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage").applyTo(this.context);
|
||||
public void statusPageUrlPathAndManagementPortKabobCase() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.status-page-url-path=/myStatusPage")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlAndPreferIpAddress() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "eureka.instance.hostname=foo",
|
||||
"eureka.instance.prefer-ip-address:true").applyTo(this.context);
|
||||
public void statusPageUrlAndPreferIpAddress() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.hostname=foo", "eureka.instance.prefer-ip-address:true")
|
||||
.applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
|
||||
assertThat(instance.getStatusPageUrl()).as("statusPageUrl is wrong")
|
||||
.isEqualTo("http://" + instance.getIpAddress() + ":9999/actuator/info");
|
||||
@@ -387,14 +369,15 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageAndHealthCheckUrlsShouldSetUserDefinedIpAddress() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999", "eureka.instance.hostname=foo",
|
||||
"eureka.instance.ip-address:192.168.13.90", "eureka.instance.prefer-ip-address:true")
|
||||
.applyTo(this.context);
|
||||
public void statusPageAndHealthCheckUrlsShouldSetUserDefinedIpAddress() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.hostname=foo",
|
||||
"eureka.instance.ip-address:192.168.13.90",
|
||||
"eureka.instance.prefer-ip-address:true").applyTo(this.context);
|
||||
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
|
||||
assertThat(instance.getStatusPageUrl()).as("statusPageUrl is wrong")
|
||||
.isEqualTo("http://192.168.13.90:9999/actuator/info");
|
||||
@@ -403,82 +386,88 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortKabobCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck").applyTo(this.context);
|
||||
public void healthCheckUrlPathAndManagementPortKabobCase() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.health-check-url-path=/myHealthCheck")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().contains("/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void statusPageUrlPathAndManagementPortUpperCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999").applyTo(this.context);
|
||||
addSystemEnvironment(this.context.getEnvironment(), "EUREKA_INSTANCE_STATUS_PAGE_URL_PATH=/myStatusPage");
|
||||
public void statusPageUrlPathAndManagementPortUpperCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999")
|
||||
.applyTo(this.context);
|
||||
addSystemEnvironment(this.context.getEnvironment(),
|
||||
"EUREKA_INSTANCE_STATUS_PAGE_URL_PATH=/myStatusPage");
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("/myStatusPage"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void healthCheckUrlPathAndManagementPortUpperCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999").applyTo(this.context);
|
||||
addSystemEnvironment(this.context.getEnvironment(), "EUREKA_INSTANCE_HEALTH_CHECK_URL_PATH=/myHealthCheck");
|
||||
public void healthCheckUrlPathAndManagementPortUpperCase() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999")
|
||||
.applyTo(this.context);
|
||||
addSystemEnvironment(this.context.getEnvironment(),
|
||||
"EUREKA_INSTANCE_HEALTH_CHECK_URL_PATH=/myHealthCheck");
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getHealthCheckUrl().contains("/myHealthCheck"))
|
||||
.as("Wrong health check: " + instance.getHealthCheckUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void hostname() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999", "eureka.instance.hostname=foo")
|
||||
.applyTo(this.context);
|
||||
public void hostname() {
|
||||
TestPropertyValues.of("server.port=8989", "management.server.port=9999",
|
||||
"eureka.instance.hostname=foo").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
EurekaInstanceConfigBean instance = this.context.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("foo")).as("Wrong status page: " + instance.getStatusPageUrl())
|
||||
.isTrue();
|
||||
EurekaInstanceConfigBean instance = this.context
|
||||
.getBean(EurekaInstanceConfigBean.class);
|
||||
assertThat(instance.getStatusPageUrl().contains("foo"))
|
||||
.as("Wrong status page: " + instance.getStatusPageUrl()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshScopedBeans() {
|
||||
public void refreshScopedBeans() {
|
||||
setupContext(RefreshAutoConfiguration.class);
|
||||
assertThat(this.context.getBeanDefinition("eurekaClient").getBeanClassName())
|
||||
.startsWith(GenericScope.class.getName() + "$LockedScopedProxyFactoryBean");
|
||||
assertThat(this.context.getBeanDefinition("eurekaApplicationInfoManager").getBeanClassName())
|
||||
.startsWith(GenericScope.class.getName() + "$LockedScopedProxyFactoryBean");
|
||||
.startsWith(
|
||||
GenericScope.class.getName() + "$LockedScopedProxyFactoryBean");
|
||||
assertThat(this.context.getBeanDefinition("eurekaApplicationInfoManager")
|
||||
.getBeanClassName()).startsWith(
|
||||
GenericScope.class.getName() + "$LockedScopedProxyFactoryBean");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
@Test
|
||||
void shouldReregisterHealthCheckHandlerAfterRefresh() throws Exception {
|
||||
TestPropertyValues
|
||||
.of("eureka.client.healthcheck.enabled=true", "spring.cloud.config.import-check.enabled=false",
|
||||
"spring.cloud.refresh.additionalPropertySourcesToRetain=test")
|
||||
public void shouldReregisterHealthCheckHandlerAfterRefresh() throws Exception {
|
||||
TestPropertyValues.of("eureka.client.healthcheck.enabled=true")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
|
||||
setupContext(RefreshAutoConfiguration.class,
|
||||
AutoServiceRegistrationConfiguration.class);
|
||||
|
||||
EurekaClient oldEurekaClient = getLazyInitEurekaClient();
|
||||
|
||||
HealthCheckHandler healthCheckHandler = this.context.getBean("eurekaHealthCheckHandler",
|
||||
HealthCheckHandler.class);
|
||||
HealthCheckHandler healthCheckHandler = this.context
|
||||
.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
|
||||
|
||||
assertThat(healthCheckHandler).isInstanceOf(EurekaHealthCheckHandler.class);
|
||||
assertThat(oldEurekaClient.getHealthCheckHandler()).isSameAs(healthCheckHandler);
|
||||
|
||||
ContextRefresher refresher = this.context.getBean(ContextRefresher.class);
|
||||
if (refresher instanceof ApplicationListener) {
|
||||
ApplicationListener<ApplicationPreparedEvent> listener = (ApplicationListener) refresher;
|
||||
listener.onApplicationEvent(
|
||||
new ApplicationPreparedEvent(Mockito.mock(SpringApplication.class), new String[0], this.context));
|
||||
}
|
||||
ContextRefresher refresher = this.context.getBean("contextRefresher",
|
||||
ContextRefresher.class);
|
||||
refresher.refresh();
|
||||
|
||||
EurekaClient newEurekaClient = getLazyInitEurekaClient();
|
||||
HealthCheckHandler newHealthCheckHandler = this.context.getBean("eurekaHealthCheckHandler",
|
||||
HealthCheckHandler.class);
|
||||
HealthCheckHandler newHealthCheckHandler = this.context
|
||||
.getBean("eurekaHealthCheckHandler", HealthCheckHandler.class);
|
||||
|
||||
assertThat(healthCheckHandler).isSameAs(newHealthCheckHandler);
|
||||
assertThat(oldEurekaClient).isNotSameAs(newEurekaClient);
|
||||
@@ -486,12 +475,14 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCloseDiscoveryClient() throws Exception {
|
||||
TestPropertyValues.of("eureka.client.healthcheck.enabled=true").applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class, AutoServiceRegistrationConfiguration.class);
|
||||
public void shouldCloseDiscoveryClient() throws Exception {
|
||||
TestPropertyValues.of("eureka.client.healthcheck.enabled=true")
|
||||
.applyTo(this.context);
|
||||
setupContext(RefreshAutoConfiguration.class,
|
||||
AutoServiceRegistrationConfiguration.class);
|
||||
|
||||
AtomicBoolean isShutdown = (AtomicBoolean) ReflectionTestUtils.getField(getLazyInitEurekaClient(),
|
||||
"isShutdown");
|
||||
AtomicBoolean isShutdown = (AtomicBoolean) ReflectionTestUtils
|
||||
.getField(getLazyInitEurekaClient(), "isShutdown");
|
||||
|
||||
assertThat(isShutdown.get()).isFalse();
|
||||
|
||||
@@ -501,9 +492,9 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicAuth() {
|
||||
TestPropertyValues
|
||||
.of("server.port=8989", "eureka.client.serviceUrl.defaultZone=https://user:foo@example.com:80/eureka")
|
||||
public void basicAuth() {
|
||||
TestPropertyValues.of("server.port=8989",
|
||||
"eureka.client.serviceUrl.defaultZone=https://user:foo@example.com:80/eureka")
|
||||
.applyTo(this.context);
|
||||
setupContext(MockClientConfiguration.class);
|
||||
// ApacheHttpClient4 http = this.context.getBean(ApacheHttpClient4.class);
|
||||
@@ -511,7 +502,7 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultAppName() throws Exception {
|
||||
public void testDefaultAppName() throws Exception {
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppname()).isEqualTo("unknown");
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).isEqualTo("unknown");
|
||||
@@ -519,7 +510,7 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAppName() throws Exception {
|
||||
public void testAppName() throws Exception {
|
||||
TestPropertyValues.of("spring.application.name=mytest").applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppname()).isEqualTo("mytest");
|
||||
@@ -528,15 +519,18 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAppNameUpper() throws Exception {
|
||||
addSystemEnvironment(this.context.getEnvironment(), "SPRING_APPLICATION_NAME=mytestupper");
|
||||
public void testAppNameUpper() throws Exception {
|
||||
addSystemEnvironment(this.context.getEnvironment(),
|
||||
"SPRING_APPLICATION_NAME=mytestupper");
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppname()).isEqualTo("mytestupper");
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).isEqualTo("mytestupper");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName()).isEqualTo("mytestupper");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName())
|
||||
.isEqualTo("mytestupper");
|
||||
}
|
||||
|
||||
private void addSystemEnvironment(ConfigurableEnvironment environment, String... pairs) {
|
||||
private void addSystemEnvironment(ConfigurableEnvironment environment,
|
||||
String... pairs) {
|
||||
MutablePropertySources sources = environment.getPropertySources();
|
||||
Map<String, Object> map = getOrAdd(sources, "testsysenv");
|
||||
for (String pair : pairs) {
|
||||
@@ -548,7 +542,8 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static Map<String, Object> getOrAdd(MutablePropertySources sources, String name) {
|
||||
private static Map<String, Object> getOrAdd(MutablePropertySources sources,
|
||||
String name) {
|
||||
if (sources.contains(name)) {
|
||||
return (Map<String, Object>) sources.get(name).getSource();
|
||||
}
|
||||
@@ -570,21 +565,23 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInstanceNamePreferred() throws Exception {
|
||||
addSystemEnvironment(this.context.getEnvironment(), "SPRING_APPLICATION_NAME=mytestspringappname");
|
||||
TestPropertyValues.of("eureka.instance.appname=mytesteurekaappname").applyTo(this.context);
|
||||
public void testInstanceNamePreferred() throws Exception {
|
||||
addSystemEnvironment(this.context.getEnvironment(),
|
||||
"SPRING_APPLICATION_NAME=mytestspringappname");
|
||||
TestPropertyValues.of("eureka.instance.appname=mytesteurekaappname")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppname()).isEqualTo("mytesteurekaappname");
|
||||
}
|
||||
|
||||
@Test
|
||||
void eurekaHealthIndicatorCreated() {
|
||||
public void eurekaHealthIndicatorCreated() {
|
||||
setupContext();
|
||||
this.context.getBean(EurekaHealthIndicator.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void eurekaClientClosed() {
|
||||
public void eurekaClientClosed() {
|
||||
setupContext(TestEurekaClientConfiguration.class);
|
||||
if (this.context != null) {
|
||||
CountDownLatch latch = this.context.getBean(CountDownLatch.class);
|
||||
@@ -594,25 +591,30 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void eurekaConfigNotLoadedWhenDiscoveryClientDisabled() {
|
||||
TestPropertyValues.of("spring.cloud.discovery.enabled=false").applyTo(this.context);
|
||||
public void eurekaConfigNotLoadedWhenDiscoveryClientDisabled() {
|
||||
TestPropertyValues.of("spring.cloud.discovery.enabled=false")
|
||||
.applyTo(this.context);
|
||||
setupContext(TestConfiguration.class);
|
||||
assertBeanNotPresent(EurekaClientConfigBean.class);
|
||||
assertBeanNotPresent(EurekaInstanceConfigBean.class);
|
||||
assertBeanNotPresent(DiscoveryClient.class);
|
||||
assertBeanNotPresent(EurekaServiceRegistry.class);
|
||||
assertBeanNotPresent(EurekaClient.class);
|
||||
assertBeanNotPresent(EurekaDiscoveryClientConfiguration.Marker.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotHaveDiscoveryClientWhenBlockingDiscoveryDisabled() {
|
||||
public void shouldNotHaveDiscoveryClientWhenBlockingDiscoveryDisabled() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(UtilAutoConfiguration.class,
|
||||
DiscoveryClientOptionalArgsConfiguration.class, EurekaClientAutoConfiguration.class,
|
||||
DiscoveryClientOptionalArgsConfiguration.class,
|
||||
EurekaClientAutoConfiguration.class,
|
||||
EurekaDiscoveryClientConfiguration.class))
|
||||
.withPropertyValues("spring.cloud.discovery.blocking.enabled=false").run(context -> {
|
||||
.withPropertyValues("spring.cloud.discovery.blocking.enabled=false")
|
||||
.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(DiscoveryClient.class);
|
||||
assertThat(context).doesNotHaveBean(DiscoveryClientHealthIndicator.class);
|
||||
assertThat(context)
|
||||
.doesNotHaveBean(DiscoveryClientHealthIndicator.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -639,7 +641,9 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
private void testSecurePort(String propName) {
|
||||
TestPropertyValues.of("eureka.instance.secure-port-enabled=true", propName + ":8443").applyTo(this.context);
|
||||
TestPropertyValues
|
||||
.of("eureka.instance.secure-port-enabled=true", propName + ":8443")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getSecurePort()).isEqualTo(8443);
|
||||
}
|
||||
@@ -649,8 +653,8 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
private EurekaClient getLazyInitEurekaClient() throws Exception {
|
||||
return (EurekaClient) ((Advised) this.context.getBean("eurekaClient", EurekaClient.class)).getTargetSource()
|
||||
.getTarget();
|
||||
return (EurekaClient) ((Advised) this.context.getBean("eurekaClient",
|
||||
EurekaClient.class)).getTargetSource().getTarget();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@@ -669,9 +673,10 @@ class EurekaClientAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Bean(destroyMethod = "shutdown")
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class, search = SearchStrategy.CURRENT)
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager, EurekaClientConfig config,
|
||||
ApplicationContext context) {
|
||||
@ConditionalOnMissingBean(value = EurekaClient.class,
|
||||
search = SearchStrategy.CURRENT)
|
||||
public EurekaClient eurekaClient(ApplicationInfoManager manager,
|
||||
EurekaClientConfig config, ApplicationContext context) {
|
||||
return new CloudEurekaClient(manager, config, null, context) {
|
||||
@Override
|
||||
public synchronized void shutdown() {
|
||||
|
||||
+53
-34
@@ -18,8 +18,8 @@ package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
@@ -34,70 +34,88 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
class EurekaClientConfigBeanTests {
|
||||
public class EurekaClientConfigBeanTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@AfterEach
|
||||
void init() {
|
||||
@After
|
||||
public void init() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicBinding() {
|
||||
TestPropertyValues.of("eureka.client.proxyHost=example.com").applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
public void basicBinding() {
|
||||
TestPropertyValues.of("eureka.client.proxyHost=example.com")
|
||||
.applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getProxyHost()).isEqualTo("example.com");
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getProxyHost())
|
||||
.isEqualTo("example.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceUrl() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:https://example.com").applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
public void serviceUrl() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:https://example.com")
|
||||
.applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getServiceUrl().toString())
|
||||
.isEqualTo("{defaultZone=https://example.com}");
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone()).isEqualTo("[https://example.com/]");
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getServiceUrl()
|
||||
.toString()).isEqualTo("{defaultZone=https://example.com}");
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone())
|
||||
.isEqualTo("[https://example.com/]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceUrlWithCompositePropertySource() {
|
||||
public void serviceUrlWithCompositePropertySource() {
|
||||
CompositePropertySource source = new CompositePropertySource("composite");
|
||||
this.context.getEnvironment().getPropertySources().addFirst(source);
|
||||
source.addPropertySource(new MapPropertySource("config", Collections.<String, Object>singletonMap(
|
||||
"eureka.client.serviceUrl.defaultZone",
|
||||
"https://example.com,https://example2.com, https://www.hugedomains.com/domain_profile.cfm?d=example3&e=com")));
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
source.addPropertySource(new MapPropertySource("config",
|
||||
Collections.<String, Object>singletonMap(
|
||||
"eureka.client.serviceUrl.defaultZone",
|
||||
"https://example.com,https://example2.com, https://www.hugedomains.com/domain_profile.cfm?d=example3&e=com")));
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getServiceUrl().toString()).isEqualTo(
|
||||
"{defaultZone=https://example.com,https://example2.com, https://www.hugedomains.com/domain_profile.cfm?d=example3&e=com}");
|
||||
assertThat(this.context.getBean(EurekaClientConfigBean.class).getServiceUrl()
|
||||
.toString()).isEqualTo(
|
||||
"{defaultZone=https://example.com,https://example2.com, https://www.hugedomains.com/domain_profile.cfm?d=example3&e=com}");
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone()).isEqualTo(
|
||||
"[https://example.com/, https://example2.com/, https://www.hugedomains.com/domain_profile.cfm?d=example3&e=com/]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceUrlWithDefault() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:https://example.com").applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
public void serviceUrlWithDefault() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:https://example.com")
|
||||
.applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone()).isEqualTo("[https://example.com/]");
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone())
|
||||
.isEqualTo("[https://example.com/]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceUrlWithCustomZone() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.customZone:https://custom-example.com").applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
public void serviceUrlWithCustomZone() {
|
||||
TestPropertyValues
|
||||
.of("eureka.client.serviceUrl.customZone:https://custom-example.com")
|
||||
.applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(getEurekaServiceUrls("customZone")).isEqualTo("[https://custom-example.com/]");
|
||||
assertThat(getEurekaServiceUrls("customZone"))
|
||||
.isEqualTo("[https://custom-example.com/]");
|
||||
}
|
||||
|
||||
@Test
|
||||
void serviceUrlWithEmptyServiceUrls() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:").applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
public void serviceUrlWithEmptyServiceUrls() {
|
||||
TestPropertyValues.of("eureka.client.serviceUrl.defaultZone:")
|
||||
.applyTo(this.context);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertThat(getEurekaServiceUrlsForDefaultZone()).isEqualTo("[]");
|
||||
}
|
||||
@@ -107,7 +125,8 @@ class EurekaClientConfigBeanTests {
|
||||
}
|
||||
|
||||
private String getEurekaServiceUrls(String myZone) {
|
||||
return this.context.getBean(EurekaClientConfigBean.class).getEurekaServerServiceUrls(myZone).toString();
|
||||
return this.context.getBean(EurekaClientConfigBean.class)
|
||||
.getEurekaServerServiceUrls(myZone).toString();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
+42
-33
@@ -19,19 +19,19 @@ package org.springframework.cloud.netflix.eureka;
|
||||
import java.util.List;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.boot.actuate.health.AbstractHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.Health;
|
||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||
import org.springframework.boot.actuate.health.OrderedHealthAggregator;
|
||||
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
|
||||
import org.springframework.boot.actuate.health.SimpleStatusAggregator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryClientHealthIndicator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthContributor;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryCompositeHealthIndicator;
|
||||
import org.springframework.cloud.client.discovery.health.DiscoveryHealthIndicator;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
@@ -45,33 +45,35 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Jakub Narloch
|
||||
* @author Nowrin Anwar Joyita
|
||||
*/
|
||||
class EurekaHealthCheckHandlerTests {
|
||||
public class EurekaHealthCheckHandlerTests {
|
||||
|
||||
private EurekaHealthCheckHandler healthCheckHandler;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
private EurekaHealthCheckHandler healthCheckHandlerWithStatusAggregator;
|
||||
|
||||
healthCheckHandler = new EurekaHealthCheckHandler(new SimpleStatusAggregator());
|
||||
@Before
|
||||
public void setUp() {
|
||||
healthCheckHandler = new EurekaHealthCheckHandler(new OrderedHealthAggregator());
|
||||
healthCheckHandlerWithStatusAggregator = new EurekaHealthCheckHandler(
|
||||
new SimpleStatusAggregator());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testNoHealthCheckRegistered() {
|
||||
|
||||
public void testNoHealthCheckRegistered() {
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.UNKNOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAllUp() throws Exception {
|
||||
initialize(UpHealthConfiguration.class, ReactiveUpHealthConfiguration.class);
|
||||
public void testAllUp() throws Exception {
|
||||
initialize(UpHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.UP);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testHealthCheckNotReturnedWhenStopped() throws Exception {
|
||||
public void testHealthCheckNotReturnedWhenStopped() throws Exception {
|
||||
initialize(UpHealthConfiguration.class);
|
||||
|
||||
healthCheckHandler.stop();
|
||||
@@ -84,7 +86,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWithBlockingIndicators() throws Exception {
|
||||
public void testDownWithBlockingIndicators() throws Exception {
|
||||
initialize(UpHealthConfiguration.class, DownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -92,31 +94,35 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWithReactiveIndicators() throws Exception {
|
||||
public void testDownWithReactiveIndicators() throws Exception {
|
||||
initialize(ReactiveUpHealthConfiguration.class,
|
||||
ReactiveDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandlerWithStatusAggregator
|
||||
.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownWhenBlockingIndicatorUpAndReactiveDown() throws Exception {
|
||||
initialize(UpHealthConfiguration.class, ReactiveDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
InstanceStatus status = healthCheckHandlerWithStatusAggregator
|
||||
.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWhenBlockingIndicatorUpAndReactiveDown() throws Exception {
|
||||
initialize(ReactiveUpHealthConfiguration.class, DownHealthConfiguration.class);
|
||||
public void testDownWhenBlockingIndicatorDownAndReactiveUp() throws Exception {
|
||||
initialize(DownHealthConfiguration.class, ReactiveUpHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = this.healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
InstanceStatus status = healthCheckHandlerWithStatusAggregator
|
||||
.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDownWhenBlockingIndicatorDownAndReactiveUp() throws Exception {
|
||||
initialize(ReactiveUpHealthConfiguration.class, ReactiveDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = this.healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
assertThat(status).isEqualTo(InstanceStatus.DOWN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUnknown() throws Exception {
|
||||
public void testUnknown() throws Exception {
|
||||
initialize(FatalHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UNKNOWN);
|
||||
@@ -124,8 +130,7 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // FIXME: 3.0.0
|
||||
void testEurekaIgnored() throws Exception {
|
||||
public void testEurekaIgnored() throws Exception {
|
||||
initialize(EurekaDownHealthConfiguration.class);
|
||||
|
||||
InstanceStatus status = healthCheckHandler.getStatus(InstanceStatus.UP);
|
||||
@@ -133,9 +138,12 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
private void initialize(Class<?>... configurations) throws Exception {
|
||||
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(configurations);
|
||||
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(
|
||||
configurations);
|
||||
healthCheckHandler.setApplicationContext(applicationContext);
|
||||
healthCheckHandler.afterPropertiesSet();
|
||||
healthCheckHandlerWithStatusAggregator.setApplicationContext(applicationContext);
|
||||
healthCheckHandlerWithStatusAggregator.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public static class UpHealthConfiguration {
|
||||
@@ -231,9 +239,10 @@ class EurekaHealthCheckHandlerTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DiscoveryCompositeHealthContributor discoveryCompositeHealthContributor(
|
||||
public DiscoveryCompositeHealthIndicator discoveryCompositeHealthIndicator(
|
||||
List<DiscoveryHealthIndicator> indicators) {
|
||||
return new DiscoveryCompositeHealthContributor(indicators);
|
||||
return new DiscoveryCompositeHealthIndicator(new OrderedHealthAggregator(),
|
||||
indicators);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+84
-62
@@ -17,10 +17,9 @@
|
||||
package org.springframework.cloud.netflix.eureka;
|
||||
|
||||
import com.netflix.appinfo.InstanceInfo.InstanceStatus;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanCreationException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -44,7 +43,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
* @author Ryan Baxter
|
||||
* @author Tim Ysewyn
|
||||
*/
|
||||
class EurekaInstanceConfigBeanTests {
|
||||
public class EurekaInstanceConfigBeanTests {
|
||||
|
||||
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
|
||||
@@ -52,8 +51,8 @@ class EurekaInstanceConfigBeanTests {
|
||||
|
||||
private String ipAddress;
|
||||
|
||||
@BeforeEach
|
||||
void init() throws Exception {
|
||||
@Before
|
||||
public void init() throws Exception {
|
||||
try (InetUtils utils = new InetUtils(new InetUtilsProperties())) {
|
||||
InetUtils.HostInfo hostInfo = utils.findFirstNonLoopbackHostInfo();
|
||||
this.hostName = hostInfo.getHostname();
|
||||
@@ -61,29 +60,30 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void clear() {
|
||||
@After
|
||||
public void clear() {
|
||||
if (this.context != null) {
|
||||
this.context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void basicBinding() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void basicBinding() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppGroupName()).isEqualTo("mygroup");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nonSecurePort() {
|
||||
public void nonSecurePort() {
|
||||
TestPropertyValues.of("eureka.instance.nonSecurePort:8888").applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getNonSecurePort()).isEqualTo(8888);
|
||||
}
|
||||
|
||||
@Test
|
||||
void instanceId() {
|
||||
public void instanceId() {
|
||||
TestPropertyValues.of("eureka.instance.instanceId:special").applyTo(this.context);
|
||||
setupContext();
|
||||
EurekaInstanceConfigBean instance = getInstanceConfig();
|
||||
@@ -91,8 +91,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialHostName() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void initialHostName() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
if (this.hostName != null) {
|
||||
assertThat(getInstanceConfig().getHostname()).isEqualTo(this.hostName);
|
||||
@@ -100,8 +101,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshHostName() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void refreshHostName() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
ReflectionTestUtils.setField(getInstanceConfig(), "hostname", "marvin");
|
||||
assertThat(getInstanceConfig().getHostname()).isEqualTo("marvin");
|
||||
@@ -112,8 +114,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshHostNameWhenSetByUser() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void refreshHostNameWhenSetByUser() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
getInstanceConfig().setHostname("marvin");
|
||||
assertThat(getInstanceConfig().getHostname()).isEqualTo("marvin");
|
||||
@@ -122,8 +125,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void initialIpAddress() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void initialIpAddress() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
if (this.ipAddress != null) {
|
||||
assertThat(getInstanceConfig().getIpAddress()).isEqualTo(this.ipAddress);
|
||||
@@ -131,8 +135,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshIpAddress() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void refreshIpAddress() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
ReflectionTestUtils.setField(getInstanceConfig(), "ipAddress", "10.0.0.1");
|
||||
assertThat(getInstanceConfig().getIpAddress()).isEqualTo("10.0.0.1");
|
||||
@@ -143,8 +148,9 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshIpAddressWhenSetByUser() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup").applyTo(this.context);
|
||||
public void refreshIpAddressWhenSetByUser() {
|
||||
TestPropertyValues.of("eureka.instance.appGroupName=mygroup")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
getInstanceConfig().setIpAddress("10.0.0.1");
|
||||
assertThat(getInstanceConfig().getIpAddress()).isEqualTo("10.0.0.1");
|
||||
@@ -153,28 +159,31 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultInitialStatus() {
|
||||
public void testDefaultInitialStatus() {
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInitialStatus()).as("initialStatus wrong").isEqualTo(InstanceStatus.UP);
|
||||
assertThat(getInstanceConfig().getInitialStatus()).as("initialStatus wrong")
|
||||
.isEqualTo(InstanceStatus.UP);
|
||||
}
|
||||
|
||||
void testBadInitialStatus() {
|
||||
@Test(expected = BeanCreationException.class)
|
||||
public void testBadInitialStatus() {
|
||||
TestPropertyValues.of("eureka.instance.initial-status:FOO").applyTo(this.context);
|
||||
Assertions.assertThrows(BeanCreationException.class, () -> {
|
||||
setupContext();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomInitialStatus() {
|
||||
TestPropertyValues.of("eureka.instance.initial-status:STARTING").applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInitialStatus()).as("initialStatus wrong").isEqualTo(InstanceStatus.STARTING);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPreferIpAddress() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.preferIpAddress:true").applyTo(this.context);
|
||||
public void testCustomInitialStatus() {
|
||||
TestPropertyValues.of("eureka.instance.initial-status:STARTING")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInitialStatus()).as("initialStatus wrong")
|
||||
.isEqualTo(InstanceStatus.STARTING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPreferIpAddress() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.preferIpAddress:true")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
EurekaInstanceConfigBean instance = getInstanceConfig();
|
||||
assertThat(getInstanceConfig().getHostname().equals(instance.getIpAddress()))
|
||||
@@ -183,57 +192,70 @@ class EurekaInstanceConfigBeanTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultVirtualHostName() throws Exception {
|
||||
public void testDefaultVirtualHostName() throws Exception {
|
||||
TestPropertyValues.of("spring.application.name:myapp").applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).as("virtualHostName wrong").isEqualTo("myapp");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName()).as("secureVirtualHostName wrong").isEqualTo("myapp");
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).as("virtualHostName wrong")
|
||||
.isEqualTo("myapp");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName())
|
||||
.as("secureVirtualHostName wrong").isEqualTo("myapp");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomVirtualHostName() throws Exception {
|
||||
TestPropertyValues.of("spring.application.name:myapp", "eureka.instance.virtualHostName=myvirthost",
|
||||
"eureka.instance.secureVirtualHostName=mysecurevirthost").applyTo(this.context);
|
||||
public void testCustomVirtualHostName() throws Exception {
|
||||
TestPropertyValues
|
||||
.of("spring.application.name:myapp",
|
||||
"eureka.instance.virtualHostName=myvirthost",
|
||||
"eureka.instance.secureVirtualHostName=mysecurevirthost")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).as("virtualHostName wrong").isEqualTo("myvirthost");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName()).as("secureVirtualHostName wrong")
|
||||
.isEqualTo("mysecurevirthost");
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).as("virtualHostName wrong")
|
||||
.isEqualTo("myvirthost");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName())
|
||||
.as("secureVirtualHostName wrong").isEqualTo("mysecurevirthost");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultAppName() throws Exception {
|
||||
public void testDefaultAppName() throws Exception {
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getAppname()).as("default app name is wrong").isEqualTo("unknown");
|
||||
assertThat(getInstanceConfig().getVirtualHostName()).as("default virtual hostname is wrong")
|
||||
.isEqualTo("unknown");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName()).as("default secure virtual hostname is wrong")
|
||||
assertThat(getInstanceConfig().getAppname()).as("default app name is wrong")
|
||||
.isEqualTo("unknown");
|
||||
assertThat(getInstanceConfig().getVirtualHostName())
|
||||
.as("default virtual hostname is wrong").isEqualTo("unknown");
|
||||
assertThat(getInstanceConfig().getSecureVirtualHostName())
|
||||
.as("default secure virtual hostname is wrong").isEqualTo("unknown");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomInstanceId() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.instanceId=myinstance").applyTo(this.context);
|
||||
public void testCustomInstanceId() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.instanceId=myinstance")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("instance id is wrong").isEqualTo("myinstance");
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("instance id is wrong")
|
||||
.isEqualTo("myinstance");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testCustomInstanceIdWithMetadata() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.metadataMap.instanceId=myinstance").applyTo(this.context);
|
||||
public void testCustomInstanceIdWithMetadata() throws Exception {
|
||||
TestPropertyValues.of("eureka.instance.metadataMap.instanceId=myinstance")
|
||||
.applyTo(this.context);
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("instance id is wrong").isEqualTo("myinstance");
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("instance id is wrong")
|
||||
.isEqualTo("myinstance");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDefaultInstanceId() throws Exception {
|
||||
public void testDefaultInstanceId() throws Exception {
|
||||
setupContext();
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("default instance id is wrong").isEqualTo(null);
|
||||
assertThat(getInstanceConfig().getInstanceId()).as("default instance id is wrong")
|
||||
.isEqualTo(null);
|
||||
}
|
||||
|
||||
private void setupContext() {
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class, TestConfiguration.class);
|
||||
this.context.register(PropertyPlaceholderAutoConfiguration.class,
|
||||
TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user