Compare commits

..
19 Commits
Author SHA1 Message Date
Olga MaciaszekSharma fb7c68bfb5 Going back to SC Build snapshots. 2021-11-17 21:31:34 +01:00
Olga MaciaszekSharma 953e4136f0 Going back to snapshots. 2021-11-17 21:16:41 +01:00
Olga MaciaszekSharma 7d83bf71ec Merge remote-tracking branch 'origin/2.2.x' into 2.2.x 2021-11-17 20:54:37 +01:00
Olga MaciaszekSharma 53199b4704 Revert "Set spring-cloud-netflix-hystrix-contract version to 2.2.10.RELEASE"
This reverts commit 56fe6e616b.
2021-11-17 20:52:23 +01:00
Olga MaciaszekSharma a568481baa Revert "Modify build script."
This reverts commit 80a0b53612.
2021-11-17 20:52:06 +01:00
Olga MaciaszekSharma b433afb3ba Revert "Temporarily disable contract tests."
This reverts commit acc0e3b735.
2021-11-17 20:51:43 +01:00
buildmaster 296d7020b9 Bumping versions 2021-11-17 19:42:43 +00:00
Olga MaciaszekSharma acc0e3b735 Temporarily disable contract tests. 2021-11-17 20:31:08 +01:00
Olga MaciaszekSharma 80a0b53612 Modify build script. 2021-11-17 19:17:03 +01:00
Olga MaciaszekSharma 56fe6e616b Set spring-cloud-netflix-hystrix-contract version to 2.2.10.RELEASE 2021-11-17 19:01:50 +01:00
Olga MaciaszekSharma ab6da840b6 Remove path variable. 2021-11-16 19:43:10 +01:00
Olga MaciaszekSharma 366efb29d5 Do not resolve path with thymeleaf while returning monitor template. 2021-11-16 17:46:14 +01:00
Olga MaciaszekSharma b5ecf2df16 Fix checkstyle. 2021-11-16 13:28:21 +01:00
Kaveh Shamsi 79d3355924 Fix the typo in the docs 2021-10-04 18:35:28 +02:00
buildmaster d16d9ec858 Bumping versions to 2.2.10.BUILD-SNAPSHOT after release 2021-07-06 14:40:37 +00:00
buildmaster 146484a356 Going back to snapshots 2021-07-06 14:40:37 +00:00
buildmaster 993f04a6c7 Update SNAPSHOT to 2.2.9.RELEASE 2021-07-06 14:36:22 +00:00
Chintan Radia e394c1227b Fix transfer encoding is set to chunked by settin entity contentLength to 0 for DELETE requests (#4002) 2021-06-15 11:10:51 +02:00
Alexander Kogut c1afe1d2a0 Handle special characters in TraceProxyRequestHelper (#3995) 2021-06-10 14:23:13 +02:00
558 changed files with 54224 additions and 2694 deletions
+46 -1
View File
@@ -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
+3
View File
@@ -0,0 +1,3 @@
releaser:
maven:
buildCommand: ./scripts/build.sh {{systemProps}}
+31 -6
View File
@@ -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>
+6
View File
@@ -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
+7
View File
@@ -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.
|===
+13 -13
View File
@@ -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
+2 -1
View File
@@ -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.
+9 -2
View File
@@ -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
+54 -7
View File
@@ -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>
+6
View File
@@ -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 ${@}
+48
View File
@@ -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>
@@ -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));
}
}
}
}
}
@@ -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);
}
}
@@ -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));
}
}
}
@@ -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);
}
}
}
@@ -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
@@ -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");
}
}
@@ -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();
}
}
@@ -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 {
}
}
@@ -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>
@@ -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());
}
}
@@ -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();
});
}
}
@@ -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);
}
}
@@ -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;
}
}
@@ -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();
}
}
}
}
@@ -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
@@ -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);
}
}
@@ -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));
}
}
}
@@ -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";
}
}
}
@@ -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();
}
}
@@ -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));
}
}
}
+47
View File
@@ -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>
@@ -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
+264 -19
View File
@@ -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>
@@ -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
@@ -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();
@@ -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);
}
}
@@ -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 {
}
@@ -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 {
@@ -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);
@@ -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;
}
@@ -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);
@@ -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 {
}
}
+50 -38
View File
@@ -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>
@@ -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
@@ -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();
}
}
@@ -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 {
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -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
@@ -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
@@ -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());
}
}
@@ -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();
}
}
@@ -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.");
}
@@ -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.");
}
}
@@ -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);
}
}
@@ -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)));
}
}
@@ -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);
}
}
@@ -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();
}
}
@@ -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));
}
}
@@ -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;
}
}
@@ -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());
}
}
@@ -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
@@ -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();
}
}
@@ -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;
}
@@ -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));
@@ -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();
}
}
@@ -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);
}
@@ -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
@@ -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;
}
@@ -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);
}
}
@@ -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);
}
@@ -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);
}
@@ -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
@@ -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);
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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) {
@@ -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 {
}
}
}
@@ -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();
}
}
@@ -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);
}
}
@@ -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);
}
}
@@ -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 {
}
@@ -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
@@ -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");
@@ -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);
}
@@ -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() {
@@ -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)
@@ -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);
}
}
@@ -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