Merge branch '5.0.x'
This commit is contained in:
@@ -204,7 +204,7 @@ WARNING: If using any of the Service Discovery-backed suppliers, adding this hea
|
||||
from the Service Registry.
|
||||
|
||||
TIP: The `HealthCheckServiceInstanceListSupplier` relies on having updated instances provided by a delegate flux. In the rare cases when you want to use a delegate that does not refresh the instances, even though the list of instances may change (such as the `DiscoveryClientServiceInstanceListSupplier` provided by us), you can set `spring.cloud.loadbalancer.health-check.refetch-instances` to `true` to have the instance list refreshed by the `HealthCheckServiceInstanceListSupplier`. You can then also adjust the refretch intervals by modifying the value of `spring.cloud.loadbalancer.health-check.refetch-instances-interval` and opt to disable the additional healthcheck repetitions by setting `spring.cloud.loadbalancer.health-check.repeat-health-check` to `false` as every instances refetch
|
||||
will also trigger a healthcheck.
|
||||
will also trigger a healthcheck.
|
||||
|
||||
`HealthCheckServiceInstanceListSupplier` uses properties prefixed with
|
||||
`spring.cloud.loadbalancer.health-check`. You can set the `initialDelay` and `interval`
|
||||
@@ -549,8 +549,41 @@ NOTE: For the properties where maps where already used, where you can specify a
|
||||
|
||||
NOTE: Starting with `4.1.0`, we have introduced the `callGetWithRequestOnDelegates` flag in `LoadBalancerProperties`. If this flag is set to `true`, `ServiceInstanceListSupplier#get(Request request)` method will be implemented to call `delegate.get(request)` in classes assignable from `DelegatingServiceInstanceListSupplier` that don't already implement that method, with the exclusion of `CachingServiceInstanceListSupplier` and `HealthCheckServiceInstanceListSupplier`, which should be placed in the instance supplier hierarchy directly after the supplier performing instance retrieval over the network, before any request-based filtering is done. It is set to `true` by default.
|
||||
|
||||
[[-aot-and-native-image-support]]
|
||||
[[aot-and-native-image-support]]
|
||||
== AOT and Native Image Support
|
||||
|
||||
Since `4.0.0`, Spring Cloud LoadBalancer supports Spring AOT transformations and native images. However, to use this feature, you need to explicitly define your `LoadBalancerClient` service IDs. You can do so by using the `value` or `name` attributes of the `@LoadBalancerClient` annotation or as values of the `spring.cloud.loadbalancer.eager-load.clients` property.
|
||||
|
||||
== LoadBalancer Integration for Spring Interface Clients AutoConfiguration
|
||||
|
||||
Since `5.0.0`, Spring Cloud LoadBalancer supports https://docs.spring.io/spring-framework/reference/7.0-SNAPSHOT/integration/rest-clients.html#rest-http-interface[Spring Interface Clients] AutoConfiguration through the `LoadBalancerRestClientHttpServiceGroupConfigurer` and `LoadBalancerWebClientHttpServiceGroupConfigurer`.
|
||||
|
||||
For each Interface Client group, if the group `baseUrl` (defined under the
|
||||
`spring.http.client.service.group.[groupName].base-url` property) is `null`, a `serviceId`-based URL for load-balancing is set up as the `baseUrl`, with `serviceId` resolved from the Interface Client `groupName`.
|
||||
|
||||
If the group `baseUrl` is `null` or its scheme is set to `lb`, a
|
||||
`DeferringLoadBalancerInterceptor` instance is picked from the application context for blocking scenarios, and a `DeferringLoadBalancerExchangeFilterFunction` instance for reactive scenarios, and is added to the group's `RestClient.Builder` or `WebClient.Builder` if available, allowing for the requests to be load-balanced.
|
||||
|
||||
For example, in an app with the following Interface Clients configuration:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@SpringBootApplication
|
||||
@ImportHttpServices(group = "verificationClient", types = {VerificationService.class,
|
||||
PersonService.class})
|
||||
public class HttpVerificationClientApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(HttpVerificationClientApplication.class, args);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is not set, it will be automatically set to `http://verificationClient`.
|
||||
The default scheme (`http`) is used initially; however, if a secure `ServiceInstance` is selected through load-balancing, it will be changed to `https`.
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that has the `lb` scheme, (for example, `lb://verificationClient/path`), it will be used with `http` being initially set as the default scheme.
|
||||
If a secure `ServiceInstance` is selected through load-balancing, the scheme will be changed to `https`.
|
||||
In both of these cases, either a `DeferringLoadBalancerInterceptor` or `DeferringLoadBalancerExchangeFilterFunction` will be added to the group's client builder, enabling the requests to be load-balanced.
|
||||
|
||||
If the `spring.http.client.service.group.verificationClient.base-url` property is set to a URL that does not have the scheme set to `lb`, (for example, `lb://verificationClient/path`), no load-balancer integration will be applied.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | `+++3.5.x+++` | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.5.x}
|
||||
|spring.cloud.compatibility-verifier.compatible-boot-versions | `+++4.0.x+++` | Default accepted versions for the Spring Boot dependency. You can set {@code x} for the patch version if you don't want to specify a concrete value. Example: {@code 3.5.x}
|
||||
|spring.cloud.compatibility-verifier.enabled | `+++false+++` | Enables creation of Spring Cloud compatibility verification.
|
||||
|spring.cloud.config.allow-override | `+++true+++` | Flag to indicate that {@link #isOverrideSystemProperties() systemPropertiesOverride} can be used. Set to false to prevent users from changing the default accidentally. Default true.
|
||||
|spring.cloud.config.initialize-on-context-refresh | `+++false+++` | Flag to initialize bootstrap configuration on context refresh event. Default false.
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud Commons Docs</name>
|
||||
|
||||
4
pom.xml
4
pom.xml
@@ -5,7 +5,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>Spring Cloud Commons Parent</name>
|
||||
<description>Spring Cloud Commons Parent</description>
|
||||
@@ -13,7 +13,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-build</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<scm>
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-commons-dependencies</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-commons-dependencies</name>
|
||||
<description>Spring Cloud Commons Dependencies</description>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -30,6 +30,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
|
||||
@@ -110,6 +111,15 @@ public class LoadBalancerAutoConfiguration {
|
||||
return new LoadBalancerRestTemplateBuilderBeanPostProcessor<>(loadBalancerInterceptorProvider, context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean({ HttpClientServiceProperties.class, ReactiveLoadBalancer.Factory.class })
|
||||
@ConditionalOnMissingBean(LoadBalancerRestClientHttpServiceGroupConfigurer.class)
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer loadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
ObjectProvider<DeferringLoadBalancerInterceptor> loadBalancerInterceptorProvider,
|
||||
HttpClientServiceProperties properties) {
|
||||
return new LoadBalancerRestClientHttpServiceGroupConfigurer(loadBalancerInterceptorProvider, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@AutoConfiguration
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -145,8 +145,7 @@ public class LoadBalancerProperties {
|
||||
this.hintHeaderName = hintHeaderName;
|
||||
}
|
||||
|
||||
// TODO: fix spelling in a major release
|
||||
public void setxForwarded(XForwarded xForwarded) {
|
||||
public void setXForwarded(XForwarded xForwarded) {
|
||||
this.xForwarded = xForwarded;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.loadbalancer;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.support.RestClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.DEFAULT_SCHEME;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.constructInterfaceClientsBaseUrl;
|
||||
|
||||
/**
|
||||
* Load-balancer-specific {@link RestClientHttpServiceGroupConfigurer} implementation. If
|
||||
* the group {@code baseUrl} is {@code null}, sets up a {@code baseUrl} with LoadBalancer
|
||||
* {@code serviceId} -resolved from Interface Client {@code groupName} set as
|
||||
* {@code host}. If the group {@code baseUrl} is {@code null} or has {@code lb} set as its
|
||||
* scheme, a {@link DeferringLoadBalancerInterceptor} instance picked from application
|
||||
* context is added to the group's {@link RestClient.Builder} if available, allowing for
|
||||
* the requests to be load-balanced.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 5.0.0
|
||||
* @see RestClientHttpServiceGroupConfigurer
|
||||
* @see HttpClientServiceProperties
|
||||
*/
|
||||
public class LoadBalancerRestClientHttpServiceGroupConfigurer implements RestClientHttpServiceGroupConfigurer {
|
||||
|
||||
// Make sure Boot's configurers run before
|
||||
private static final int ORDER = 10;
|
||||
|
||||
private final SingletonSupplier<DeferringLoadBalancerInterceptor> loadBalancerInterceptorSupplier;
|
||||
|
||||
private final HttpClientServiceProperties clientServiceProperties;
|
||||
|
||||
public LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
ObjectProvider<DeferringLoadBalancerInterceptor> loadBalancerInterceptorProvider,
|
||||
HttpClientServiceProperties clientServiceProperties) {
|
||||
this.loadBalancerInterceptorSupplier = SingletonSupplier
|
||||
.ofNullable(loadBalancerInterceptorProvider::getIfAvailable);
|
||||
this.clientServiceProperties = clientServiceProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureGroups(@NonNull Groups<RestClient.Builder> groups) {
|
||||
DeferringLoadBalancerInterceptor loadBalancerInterceptor = loadBalancerInterceptorSupplier.get();
|
||||
if (loadBalancerInterceptor == null) {
|
||||
throw new IllegalStateException(
|
||||
DeferringLoadBalancerInterceptor.class.getSimpleName() + " bean not available.");
|
||||
}
|
||||
|
||||
groups.forEachGroup((group, clientBuilder, factoryBuilder) -> {
|
||||
String groupName = group.name();
|
||||
HttpClientServiceProperties.Group groupProperties = clientServiceProperties.getGroup().get(groupName);
|
||||
String baseUrlString = groupProperties == null ? null : groupProperties.getBaseUrl();
|
||||
URI existingBaseUrl = baseUrlString == null ? null : URI.create(baseUrlString);
|
||||
if (existingBaseUrl == null) {
|
||||
URI baseUrl = constructBaseUrl(groupName);
|
||||
clientBuilder.baseUrl(baseUrl);
|
||||
clientBuilder.requestInterceptor(loadBalancerInterceptor);
|
||||
}
|
||||
else if ("lb".equalsIgnoreCase(existingBaseUrl.getScheme())) {
|
||||
URI baseUrl = UriComponentsBuilder.fromUri(existingBaseUrl).scheme(DEFAULT_SCHEME).build().toUri();
|
||||
clientBuilder.baseUrl(baseUrl);
|
||||
clientBuilder.requestInterceptor(loadBalancerInterceptor);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
private URI constructBaseUrl(String groupName) {
|
||||
return constructInterfaceClientsBaseUrl(groupName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -37,12 +37,15 @@ public final class LoadBalancerUriTools {
|
||||
|
||||
private static final String PERCENTAGE_SIGN = "%";
|
||||
|
||||
private static final String DEFAULT_SCHEME = "http";
|
||||
|
||||
private static final String DEFAULT_SECURE_SCHEME = "https";
|
||||
|
||||
private static final Map<String, String> INSECURE_SCHEME_MAPPINGS;
|
||||
|
||||
/**
|
||||
* Default scheme.
|
||||
*/
|
||||
public static final String DEFAULT_SCHEME = "http";
|
||||
|
||||
static {
|
||||
INSECURE_SCHEME_MAPPINGS = new HashMap<>();
|
||||
INSECURE_SCHEME_MAPPINGS.put(DEFAULT_SCHEME, DEFAULT_SECURE_SCHEME);
|
||||
@@ -115,4 +118,8 @@ public final class LoadBalancerUriTools {
|
||||
return originalOrDefault;
|
||||
}
|
||||
|
||||
public static URI constructInterfaceClientsBaseUrl(String groupName) {
|
||||
return UriComponentsBuilder.newInstance().scheme(DEFAULT_SCHEME).host(groupName).encode().build().toUri();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
|
||||
@@ -80,7 +81,7 @@ public class RequestData {
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> buildCookies(MultiValueMap<String, HttpCookie> cookies) {
|
||||
HttpHeaders newCookies = new HttpHeaders();
|
||||
MultiValueMap<String, String> newCookies = new LinkedMultiValueMap<>();
|
||||
if (cookies != null) {
|
||||
cookies.forEach((key, value) -> value
|
||||
.forEach(cookie -> newCookies.put(cookie.getName(), Collections.singletonList(cookie.getValue()))));
|
||||
@@ -89,7 +90,7 @@ public class RequestData {
|
||||
}
|
||||
|
||||
private static MultiValueMap<String, String> buildCookiesFromHeaders(HttpHeaders headers) {
|
||||
HttpHeaders newCookies = new HttpHeaders();
|
||||
MultiValueMap<String, String> newCookies = new LinkedMultiValueMap<>();
|
||||
if (headers == null) {
|
||||
return newCookies;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -21,6 +21,8 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.http.client.reactive.service.ReactiveHttpClientServiceProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -66,6 +68,15 @@ public class LoadBalancerBeanPostProcessorAutoConfiguration {
|
||||
return new DeferringLoadBalancerExchangeFilterFunction<>(exchangeFilterFunctionProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnBean({ ReactiveHttpClientServiceProperties.class, ReactiveLoadBalancer.Factory.class })
|
||||
@ConditionalOnMissingBean(LoadBalancerWebClientHttpServiceGroupConfigurer.class)
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer loadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
ObjectProvider<DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction>> deferringExchangeFilterFunction,
|
||||
ReactiveHttpClientServiceProperties properties) {
|
||||
return new LoadBalancerWebClientHttpServiceGroupConfigurer(deferringExchangeFilterFunction, properties);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class OnAnyLoadBalancerImplementationPresentCondition extends AnyNestedCondition {
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.loadbalancer.reactive;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.http.client.reactive.service.ReactiveHttpClientServiceProperties;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties;
|
||||
import org.springframework.util.function.SingletonSupplier;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.support.WebClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.DEFAULT_SCHEME;
|
||||
import static org.springframework.cloud.client.loadbalancer.LoadBalancerUriTools.constructInterfaceClientsBaseUrl;
|
||||
|
||||
/**
|
||||
* Load-balancer-specific {@link WebClientHttpServiceGroupConfigurer} implementation. If
|
||||
* the group {@code baseUrl} is {@code null}, sets up a {@code baseUrl} with LoadBalancer
|
||||
* {@code serviceId} -resolved from Interface Client {@code groupName} set as
|
||||
* {@code host}. If the group {@code baseUrl} is {@code null} or has {@code lb} set as its
|
||||
* scheme, a {@link DeferringLoadBalancerExchangeFilterFunction} instance picked from
|
||||
* application context is added to the group's {@link WebClient.Builder} if available,
|
||||
* allowing for the requests to be load-balanced.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 5.0.0
|
||||
* @see WebClient.Builder
|
||||
* @see HttpClientServiceProperties
|
||||
*/
|
||||
public class LoadBalancerWebClientHttpServiceGroupConfigurer implements WebClientHttpServiceGroupConfigurer {
|
||||
|
||||
// Make sure Boot's configurers run before
|
||||
private static final int ORDER = 10;
|
||||
|
||||
private final SingletonSupplier<DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction>> loadBalancerFilterFunctionSupplier;
|
||||
|
||||
private final ReactiveHttpClientServiceProperties clientServiceProperties;
|
||||
|
||||
public LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
ObjectProvider<DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction>> exchangeFilterFunctionProvider,
|
||||
ReactiveHttpClientServiceProperties clientServiceProperties) {
|
||||
this.loadBalancerFilterFunctionSupplier = SingletonSupplier
|
||||
.ofNullable(exchangeFilterFunctionProvider::getIfAvailable);
|
||||
this.clientServiceProperties = clientServiceProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureGroups(Groups<WebClient.Builder> groups) {
|
||||
DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction> loadBalancerFilterFunction = loadBalancerFilterFunctionSupplier
|
||||
.get();
|
||||
if (loadBalancerFilterFunction == null) {
|
||||
throw new IllegalStateException(
|
||||
DeferringLoadBalancerExchangeFilterFunction.class.getSimpleName() + " bean not available.");
|
||||
}
|
||||
groups.forEachGroup((group, clientBuilder, factoryBuilder) -> {
|
||||
String groupName = group.name();
|
||||
ReactiveHttpClientServiceProperties.Group groupProperties = clientServiceProperties.getGroup()
|
||||
.get(groupName);
|
||||
String baseUrlString = groupProperties == null ? null : groupProperties.getBaseUrl();
|
||||
URI existingBaseUrl = baseUrlString == null ? null : URI.create(baseUrlString);
|
||||
if (existingBaseUrl == null) {
|
||||
URI baseUrl = constructBaseUrl(groupName);
|
||||
clientBuilder.baseUrl(String.valueOf(baseUrl));
|
||||
clientBuilder.filter(loadBalancerFilterFunction);
|
||||
}
|
||||
else if ("lb".equalsIgnoreCase(existingBaseUrl.getScheme())) {
|
||||
String baseUrl = UriComponentsBuilder.fromUri(existingBaseUrl)
|
||||
.scheme(DEFAULT_SCHEME)
|
||||
.build()
|
||||
.toUriString();
|
||||
clientBuilder.baseUrl(baseUrl);
|
||||
clientBuilder.filter(loadBalancerFilterFunction);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ORDER;
|
||||
}
|
||||
|
||||
private URI constructBaseUrl(String groupName) {
|
||||
return constructInterfaceClientsBaseUrl(groupName);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -22,6 +22,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.compatibility-verifier")
|
||||
public class CompatibilityVerifierProperties {
|
||||
@@ -36,7 +37,7 @@ public class CompatibilityVerifierProperties {
|
||||
* the patch version if you don't want to specify a concrete value. Example:
|
||||
* {@code 3.5.x}
|
||||
*/
|
||||
private List<String> compatibleBootVersions = List.of("3.5.x");
|
||||
private List<String> compatibleBootVersions = List.of("4.0.x");
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -27,7 +27,7 @@ import org.springframework.boot.SpringBootVersion;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Verifies if Spring Boot has proper version.
|
||||
* Verifies if Spring Boot has the proper version.
|
||||
*/
|
||||
class SpringBootVersionVerifier implements CompatibilityVerifier {
|
||||
|
||||
@@ -35,7 +35,7 @@ class SpringBootVersionVerifier implements CompatibilityVerifier {
|
||||
|
||||
final Map<String, CompatibilityPredicate> ACCEPTED_VERSIONS = new HashMap<>() {
|
||||
{
|
||||
this.put("3.5", is3_5());
|
||||
this.put("4.0", is4_0());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -70,12 +70,12 @@ class SpringBootVersionVerifier implements CompatibilityVerifier {
|
||||
return SpringBootVersion.getVersion();
|
||||
}
|
||||
|
||||
CompatibilityPredicate is3_5() {
|
||||
CompatibilityPredicate is4_0() {
|
||||
return new CompatibilityPredicate() {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Predicate for Boot 3.5";
|
||||
return "Predicate for Boot 4.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2024 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -25,9 +25,11 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerWebClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
@@ -154,6 +156,14 @@ public abstract class AbstractLoadBalancerAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadBalancerRestClientHttpServiceGroupConfigurerPresent() {
|
||||
applicationContextRunner.withUserConfiguration(OneRestClientBuilder.class).run(context -> {
|
||||
assertThat(context.getBeansOfType(LoadBalancerRestClientHttpServiceGroupConfigurer.class)).hasSize(1);
|
||||
assertThat(context.getBeansOfType(LoadBalancerWebClientHttpServiceGroupConfigurer.class)).hasSize(0);
|
||||
});
|
||||
}
|
||||
|
||||
protected abstract void assertLoadBalanced(RestClient.Builder restClientBuilder);
|
||||
|
||||
protected abstract void assertLoadBalanced(RestTemplate restTemplate);
|
||||
@@ -180,6 +190,11 @@ public abstract class AbstractLoadBalancerAutoConfigurationTests {
|
||||
return RestClient.builder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
HttpClientServiceProperties httpClientServiceProperties() {
|
||||
return new HttpClientServiceProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.loadbalancer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties;
|
||||
import org.springframework.boot.autoconfigure.http.client.service.HttpClientServiceProperties.Group;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
import org.springframework.web.service.registry.HttpServiceGroup;
|
||||
import org.springframework.web.service.registry.HttpServiceGroupConfigurer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link LoadBalancerRestClientHttpServiceGroupConfigurer}
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SuppressWarnings({ "removal" })
|
||||
class LoadBalancerRestClientHttpServiceGroupConfigurerTests {
|
||||
|
||||
private static final String GROUP_NAME = "testService";
|
||||
|
||||
private HttpClientServiceProperties clientServiceProperties;
|
||||
|
||||
private ObjectProvider<DeferringLoadBalancerInterceptor> interceptorProvider;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
DeferringLoadBalancerInterceptor interceptor = mock(DeferringLoadBalancerInterceptor.class);
|
||||
interceptorProvider = new SimpleObjectProvider<>(interceptor);
|
||||
clientServiceProperties = new HttpClientServiceProperties();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlIsNotSet() {
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer configurer = new LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
interceptorProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.requestInterceptors(interceptors -> {
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors.get(0).getClass()).isEqualTo(DeferringLoadBalancerInterceptor.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlHasLbScheme() {
|
||||
Group group = new Group();
|
||||
group.setBaseUrl("lb://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer configurer = new LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
interceptorProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.requestInterceptors(interceptors -> {
|
||||
assertThat(interceptors).hasSize(1);
|
||||
assertThat(interceptors.get(0).getClass()).isEqualTo(DeferringLoadBalancerInterceptor.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAddInterceptorWhenBaseDoesNotHaveLbScheme() {
|
||||
Group group = new Group();
|
||||
group.setBaseUrl("http://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerRestClientHttpServiceGroupConfigurer configurer = new LoadBalancerRestClientHttpServiceGroupConfigurer(
|
||||
interceptorProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.requestInterceptors(interceptors -> assertThat(interceptors).hasSize(0));
|
||||
}
|
||||
|
||||
private static class TestGroups implements HttpServiceGroupConfigurer.Groups<RestClient.Builder> {
|
||||
|
||||
RestClient.Builder builder = RestClient.builder();
|
||||
|
||||
@Override
|
||||
public HttpServiceGroupConfigurer.Groups<RestClient.Builder> filterByName(String... groupNames) {
|
||||
throw new UnsupportedOperationException("Please, implement me.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServiceGroupConfigurer.Groups<RestClient.Builder> filter(Predicate<HttpServiceGroup> predicate) {
|
||||
throw new UnsupportedOperationException("Please, implement me.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachClient(HttpServiceGroupConfigurer.ClientCallback<RestClient.Builder> configurer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachProxyFactory(HttpServiceGroupConfigurer.ProxyFactoryCallback configurer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachGroup(HttpServiceGroupConfigurer.GroupCallback<RestClient.Builder> groupConfigurer) {
|
||||
groupConfigurer.withGroup(
|
||||
new TestGroup(GROUP_NAME, HttpServiceGroup.ClientType.REST_CLIENT, new HashSet<>()), builder,
|
||||
HttpServiceProxyFactory.builder());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private record TestGroup(String name, ClientType clientType,
|
||||
Set<Class<?>> httpServiceTypes) implements HttpServiceGroup {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2012-2025 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.client.loadbalancer.reactive;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.boot.autoconfigure.http.client.reactive.service.ReactiveHttpClientServiceProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.SimpleObjectProvider;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.service.invoker.HttpServiceProxyFactory;
|
||||
import org.springframework.web.service.registry.HttpServiceGroup;
|
||||
import org.springframework.web.service.registry.HttpServiceGroupConfigurer;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link LoadBalancerWebClientHttpServiceGroupConfigurer}
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "removal" })
|
||||
class LoadBalancerWebClientHttpServiceGroupConfigurerTests {
|
||||
|
||||
private static final String GROUP_NAME = "testService";
|
||||
|
||||
private ReactiveHttpClientServiceProperties clientServiceProperties;
|
||||
|
||||
private ObjectProvider<DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction>> exchangeFilterFunctionProvider;
|
||||
|
||||
@BeforeEach
|
||||
void setup() {
|
||||
DeferringLoadBalancerExchangeFilterFunction<LoadBalancedExchangeFilterFunction> exchangeFilterFunction = mock(
|
||||
DeferringLoadBalancerExchangeFilterFunction.class);
|
||||
exchangeFilterFunctionProvider = new SimpleObjectProvider<>(exchangeFilterFunction);
|
||||
clientServiceProperties = new ReactiveHttpClientServiceProperties();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlIsNotSet() {
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer configurer = new LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
exchangeFilterFunctionProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.filters(filterFunctions -> {
|
||||
assertThat(filterFunctions).hasSize(1);
|
||||
assertThat(filterFunctions.get(0).getClass()).isEqualTo(DeferringLoadBalancerExchangeFilterFunction.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddInterceptorWhenBaseUrlHasLbScheme() {
|
||||
ReactiveHttpClientServiceProperties.Group group = new ReactiveHttpClientServiceProperties.Group();
|
||||
group.setBaseUrl("lb://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer configurer = new LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
exchangeFilterFunctionProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.filters(filterFunctions -> {
|
||||
assertThat(filterFunctions).hasSize(1);
|
||||
assertThat(filterFunctions.get(0).getClass()).isEqualTo(DeferringLoadBalancerExchangeFilterFunction.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotAddInterceptorWhenBaseDoesNotHaveLbScheme() {
|
||||
ReactiveHttpClientServiceProperties.Group group = new ReactiveHttpClientServiceProperties.Group();
|
||||
group.setBaseUrl("https://" + GROUP_NAME + "/path");
|
||||
clientServiceProperties.getGroup().put(GROUP_NAME, group);
|
||||
LoadBalancerWebClientHttpServiceGroupConfigurer configurer = new LoadBalancerWebClientHttpServiceGroupConfigurer(
|
||||
exchangeFilterFunctionProvider, clientServiceProperties);
|
||||
TestGroups groups = new TestGroups();
|
||||
|
||||
configurer.configureGroups(groups);
|
||||
|
||||
groups.builder.filters(filterFunctions -> assertThat(filterFunctions).hasSize(0));
|
||||
}
|
||||
|
||||
private static class TestGroups implements HttpServiceGroupConfigurer.Groups<WebClient.Builder> {
|
||||
|
||||
WebClient.Builder builder = WebClient.builder();
|
||||
|
||||
//
|
||||
@Override
|
||||
public HttpServiceGroupConfigurer.Groups<WebClient.Builder> filterByName(String... groupNames) {
|
||||
throw new UnsupportedOperationException("Please, implement me.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpServiceGroupConfigurer.Groups<WebClient.Builder> filter(Predicate<HttpServiceGroup> predicate) {
|
||||
throw new UnsupportedOperationException("Please, implement me.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachClient(HttpServiceGroupConfigurer.ClientCallback<WebClient.Builder> configurer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachProxyFactory(HttpServiceGroupConfigurer.ProxyFactoryCallback configurer) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEachGroup(HttpServiceGroupConfigurer.GroupCallback<WebClient.Builder> groupConfigurer) {
|
||||
groupConfigurer.withGroup(
|
||||
new TestGroup(GROUP_NAME, HttpServiceGroup.ClientType.WEB_CLIENT, new HashSet<>()), builder,
|
||||
HttpServiceProxyFactory.builder());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private record TestGroup(String name, ClientType clientType,
|
||||
Set<Class<?>> httpServiceTypes) implements HttpServiceGroup {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -23,19 +23,24 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.client.reactive.service.ReactiveHttpClientServiceProperties;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerRestClientHttpServiceGroupConfigurer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.BDDAssertions.then;
|
||||
import static org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerTestUtils.assertLoadBalanced;
|
||||
import static org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerTestUtils.getFilters;
|
||||
@@ -150,6 +155,18 @@ public class ReactorLoadBalancerClientAutoConfigurationTests {
|
||||
then(clientProperties.getHealthCheck().getInterval()).isEqualTo(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
@Test
|
||||
void loadBalancerRestClientHttpServiceGroupConfigurerPresent() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(ReactorLoadBalancerClientAutoConfiguration.class,
|
||||
LoadBalancerBeanPostProcessorAutoConfiguration.class))
|
||||
.withUserConfiguration(OneWebClientBuilder.class)
|
||||
.run(context -> {
|
||||
assertThat(context.getBeansOfType(LoadBalancerWebClientHttpServiceGroupConfigurer.class)).hasSize(1);
|
||||
assertThat(context.getBeansOfType(LoadBalancerRestClientHttpServiceGroupConfigurer.class)).hasSize(0);
|
||||
});
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext init(Class<?> config) {
|
||||
return LoadBalancerTestUtils.init(config, ReactorLoadBalancerClientAutoConfiguration.class,
|
||||
LoadBalancerBeanPostProcessorAutoConfiguration.class);
|
||||
@@ -211,6 +228,11 @@ public class ReactorLoadBalancerClientAutoConfigurationTests {
|
||||
return new TestService(loadBalancedWebClientBuilder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveHttpClientServiceProperties reactiveHttpClientServiceProperties() {
|
||||
return new ReactiveHttpClientServiceProperties();
|
||||
}
|
||||
|
||||
private static final class TestService {
|
||||
|
||||
public final WebClient webClient;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -31,6 +31,7 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
||||
import org.springframework.web.reactive.function.client.ExchangeFunction;
|
||||
@@ -75,7 +76,7 @@ class RetryableLoadBalancerExchangeFilterFunctionTests {
|
||||
when(factory.getInstance("test")).thenReturn(new TestReactiveLoadBalancer());
|
||||
when(factory.getProperties(any())).thenReturn(properties);
|
||||
when(clientRequest.headers()).thenReturn(new HttpHeaders());
|
||||
when(clientRequest.cookies()).thenReturn(new HttpHeaders());
|
||||
when(clientRequest.cookies()).thenReturn(new LinkedMultiValueMap<>());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -27,6 +27,7 @@ import static org.assertj.core.api.BDDAssertions.then;
|
||||
|
||||
/**
|
||||
* @author Marcin Grzejszczak
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class SpringBootDependencyTests {
|
||||
|
||||
@@ -176,8 +177,8 @@ public class SpringBootDependencyTests {
|
||||
@Test
|
||||
public void should_match_against_current_manifest() {
|
||||
try {
|
||||
verifyCurrentVersionFromManifest("3.5");
|
||||
verifyCurrentVersionFromManifest("3.5.x");
|
||||
verifyCurrentVersionFromManifest("4.0");
|
||||
verifyCurrentVersionFromManifest("4.0.x");
|
||||
}
|
||||
catch (AssertionError e) {
|
||||
// if (e.getMessage() != null && e.getMessage().contains("3.3.")) {
|
||||
@@ -204,7 +205,7 @@ public class SpringBootDependencyTests {
|
||||
|
||||
@Test
|
||||
public void should_match_against_current_predicate() {
|
||||
List<String> acceptedVersions = Collections.singletonList("3.0");
|
||||
List<String> acceptedVersions = Collections.singletonList("4.0");
|
||||
SpringBootVersionVerifier versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
|
||||
@Override
|
||||
String getVersionFromManifest() {
|
||||
@@ -212,7 +213,7 @@ public class SpringBootDependencyTests {
|
||||
}
|
||||
};
|
||||
versionVerifier.ACCEPTED_VERSIONS.clear();
|
||||
versionVerifier.ACCEPTED_VERSIONS.put("3.0", versionVerifier.is3_5());
|
||||
versionVerifier.ACCEPTED_VERSIONS.put("4.0", versionVerifier.is4_0());
|
||||
|
||||
VerificationResult verificationResult = versionVerifier.verify();
|
||||
|
||||
@@ -222,7 +223,7 @@ public class SpringBootDependencyTests {
|
||||
|
||||
@Test
|
||||
public void should_match_against_current_predicate_with_version_ending_with_x() {
|
||||
List<String> acceptedVersions = Collections.singletonList("3.0.x");
|
||||
List<String> acceptedVersions = Collections.singletonList("4.0.x");
|
||||
SpringBootVersionVerifier versionVerifier = new SpringBootVersionVerifier(acceptedVersions) {
|
||||
@Override
|
||||
String getVersionFromManifest() {
|
||||
@@ -230,7 +231,7 @@ public class SpringBootDependencyTests {
|
||||
}
|
||||
};
|
||||
versionVerifier.ACCEPTED_VERSIONS.clear();
|
||||
versionVerifier.ACCEPTED_VERSIONS.put("3.0", versionVerifier.is3_5());
|
||||
versionVerifier.ACCEPTED_VERSIONS.put("4.0", versionVerifier.is4_0());
|
||||
|
||||
VerificationResult verificationResult = versionVerifier.verify();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-context-integration-tests</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-context-webflux-integration-tests</artifactId>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-context</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
* Copyright 2013-2025 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.
|
||||
@@ -380,9 +380,10 @@ public final class ServiceInstanceListSupplierBuilder {
|
||||
return new HealthCheckServiceInstanceListSupplier(delegate, loadBalancerClientFactory,
|
||||
(serviceInstance, healthCheckPath) -> webClient.get()
|
||||
.uri(UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build().toUri())
|
||||
.exchange()
|
||||
.flatMap(clientResponse -> clientResponse.releaseBody()
|
||||
.thenReturn(HttpStatus.OK.equals(clientResponse.statusCode()))));
|
||||
.retrieve()
|
||||
.toBodilessEntity()
|
||||
.map(response -> HttpStatus.OK.equals(response.getStatusCode()))
|
||||
.onErrorReturn(false));
|
||||
}
|
||||
|
||||
private ServiceInstanceListSupplier blockingHealthCheckServiceInstanceListSupplier(RestTemplate restTemplate,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -65,9 +65,9 @@ class XForwardedHeadersTransformerTests {
|
||||
|
||||
HttpRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
|
||||
assertThat(newRequest.getHeaders()).containsKey("X-Forwarded-Host");
|
||||
assertThat(newRequest.getHeaders().containsHeader("X-Forwarded-Host")).isTrue();
|
||||
assertThat(newRequest.getHeaders().getFirst("X-Forwarded-Host")).isEqualTo("google.com");
|
||||
assertThat(newRequest.getHeaders()).containsKey("X-Forwarded-Proto");
|
||||
assertThat(newRequest.getHeaders().containsHeader("X-Forwarded-Proto")).isTrue();
|
||||
assertThat(newRequest.getHeaders().getFirst("X-Forwarded-Proto")).isEqualTo("https");
|
||||
}
|
||||
|
||||
@@ -78,8 +78,8 @@ class XForwardedHeadersTransformerTests {
|
||||
XForwardedHeadersTransformer transformer = new XForwardedHeadersTransformer(loadBalancerClientFactory);
|
||||
|
||||
HttpRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
assertThat(newRequest.getHeaders()).doesNotContainKey("X-Forwarded-Host");
|
||||
assertThat(newRequest.getHeaders()).doesNotContainKey("X-Forwarded-Proto");
|
||||
assertThat(newRequest.getHeaders().containsHeader("X-Forwarded-Host")).isFalse();
|
||||
assertThat(newRequest.getHeaders().containsHeader("X-Forwarded-Proto")).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2023 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -703,7 +703,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCheckUseProvidedPortForHealthCheckRequest() {
|
||||
void shouldCheckUserProvidedPortForHealthCheckRequest() {
|
||||
Throwable exception = catchThrowable(() -> {
|
||||
String serviceId = "ignored-service";
|
||||
properties.getHealthCheck().setPort(8888);
|
||||
@@ -718,7 +718,7 @@ class HealthCheckServiceInstanceListSupplierTests {
|
||||
listSupplier.isAlive(serviceInstance).block();
|
||||
});
|
||||
|
||||
assertThat(exception).hasMessageContaining("Connection refused: /127.0.0.1:888");
|
||||
assertThat(exception).hasMessageContaining("Connection refused: /127.0.0.1:8888");
|
||||
}
|
||||
|
||||
private static Stream<Arguments> healthCheckFunctions() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -74,7 +74,7 @@ class LoadBalancerServiceInstanceCookieTransformerTests {
|
||||
void shouldReturnPassedRequestWhenNoServiceInstance() {
|
||||
HttpRequest newRequest = transformer.transformRequest(request, null);
|
||||
|
||||
assertThat(newRequest.getHeaders()).doesNotContainKey(HttpHeaders.COOKIE);
|
||||
assertThat(newRequest.getHeaders().containsHeader(HttpHeaders.COOKIE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -82,7 +82,7 @@ class LoadBalancerServiceInstanceCookieTransformerTests {
|
||||
properties.getStickySession().setInstanceIdCookieName(null);
|
||||
HttpRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
|
||||
assertThat(newRequest.getHeaders()).doesNotContainKey(HttpHeaders.COOKIE);
|
||||
assertThat(newRequest.getHeaders().containsHeader(HttpHeaders.COOKIE)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -90,7 +90,7 @@ class LoadBalancerServiceInstanceCookieTransformerTests {
|
||||
properties.getStickySession().setInstanceIdCookieName("");
|
||||
HttpRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
|
||||
assertThat(newRequest.getHeaders()).doesNotContainKey(HttpHeaders.COOKIE);
|
||||
assertThat(newRequest.getHeaders().containsHeader(HttpHeaders.COOKIE)).isFalse();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.cloud.loadbalancer.core;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -31,7 +32,8 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.Request;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestData;
|
||||
import org.springframework.cloud.client.loadbalancer.RequestDataContext;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.reactive.function.client.ClientRequest;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -72,8 +74,8 @@ class RequestBasedStickySessionServiceInstanceListSupplierTests {
|
||||
|
||||
@Test
|
||||
void shouldReturnInstanceBasedOnCookieFromClientRequest() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(properties.getStickySession().getInstanceIdCookieName(), "test-1");
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
headers.put(properties.getStickySession().getInstanceIdCookieName(), Collections.singletonList("test-1"));
|
||||
when(clientRequest.cookies()).thenReturn(headers);
|
||||
Request<RequestDataContext> request = new DefaultRequest<>(
|
||||
new RequestDataContext(new RequestData(clientRequest)));
|
||||
@@ -86,8 +88,8 @@ class RequestBasedStickySessionServiceInstanceListSupplierTests {
|
||||
|
||||
@Test
|
||||
void shouldReturnAllDelegateInstancesIfInstanceBasedOnCookieFromClientRequestNotFound() {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(properties.getStickySession().getInstanceIdCookieName(), "test-4");
|
||||
MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
|
||||
headers.put(properties.getStickySession().getInstanceIdCookieName(), Collections.singletonList("test-4"));
|
||||
when(clientRequest.cookies()).thenReturn(headers);
|
||||
Request<RequestDataContext> request = new DefaultRequest<>(
|
||||
new RequestDataContext(new RequestData(clientRequest)));
|
||||
@@ -99,7 +101,7 @@ class RequestBasedStickySessionServiceInstanceListSupplierTests {
|
||||
|
||||
@Test
|
||||
void shouldReturnAllInstancesFromDelegateIfClientRequestHasNoCookie() {
|
||||
when(clientRequest.cookies()).thenReturn(new HttpHeaders());
|
||||
when(clientRequest.cookies()).thenReturn(new LinkedMultiValueMap<>());
|
||||
Request<RequestDataContext> request = new DefaultRequest<>(
|
||||
new RequestDataContext(new RequestData(clientRequest)));
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2023 the original author or authors.
|
||||
* Copyright 2013-2025 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.
|
||||
@@ -26,6 +26,7 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.client.RestClient;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
import org.springframework.web.reactive.function.client.WebClientRequestException;
|
||||
import org.springframework.web.util.UriComponentsBuilder;
|
||||
|
||||
import static org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplierBuilder.getUri;
|
||||
@@ -46,9 +47,10 @@ final class ServiceInstanceListSuppliersTestUtils {
|
||||
static BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunction(WebClient webClient) {
|
||||
return (serviceInstance, healthCheckPath) -> webClient.get()
|
||||
.uri(UriComponentsBuilder.fromUriString(getUri(serviceInstance, healthCheckPath)).build().toUri())
|
||||
.exchange()
|
||||
.flatMap(clientResponse -> clientResponse.releaseBody()
|
||||
.thenReturn(HttpStatus.OK.equals(clientResponse.statusCode())));
|
||||
.retrieve()
|
||||
.toBodilessEntity()
|
||||
.map(response -> HttpStatus.OK.equals(response.getStatusCode()))
|
||||
.onErrorReturn(throwable -> !(throwable instanceof WebClientRequestException), false);
|
||||
}
|
||||
|
||||
static BiFunction<ServiceInstance, String, Mono<Boolean>> healthCheckFunction(RestTemplate restTemplate) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012-2021 the original author or authors.
|
||||
* Copyright 2012-2025 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.
|
||||
@@ -66,9 +66,9 @@ class XForwardedHeadersTransformerTests {
|
||||
|
||||
ClientRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
|
||||
assertThat(newRequest.headers()).containsKey("X-Forwarded-Host");
|
||||
assertThat(newRequest.headers().containsHeader("X-Forwarded-Host")).isTrue();
|
||||
assertThat(newRequest.headers().getFirst("X-Forwarded-Host")).isEqualTo("spring.io");
|
||||
assertThat(newRequest.headers()).containsKey("X-Forwarded-Proto");
|
||||
assertThat(newRequest.headers().containsHeader("X-Forwarded-Proto")).isTrue();
|
||||
assertThat(newRequest.headers().getFirst("X-Forwarded-Proto")).isEqualTo("https");
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ class XForwardedHeadersTransformerTests {
|
||||
|
||||
ClientRequest newRequest = transformer.transformRequest(request, serviceInstance);
|
||||
|
||||
assertThat(newRequest.headers()).doesNotContainKey("X-Forwarded-Host");
|
||||
assertThat(newRequest.headers()).doesNotContainKey("X-Forwarded-Proto");
|
||||
assertThat(newRequest.headers().containsHeader("X-Forwarded-Host")).isFalse();
|
||||
assertThat(newRequest.headers().containsHeader("X-Forwarded-Proto")).isFalse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalanc
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMapAdapter;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -71,7 +72,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
@Test
|
||||
void shouldRecordSuccessfulTimedRequest() {
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
new LinkedMultiValueMap<>(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
Response<ServiceInstance> lbResponse = new DefaultResponse(
|
||||
new DefaultServiceInstance("test-1", "test", "test.org", 8080, false, new HashMap<>()));
|
||||
@@ -93,6 +94,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
Tag.of("serviceInstance.port", "8080"), Tag.of("status", "200"), Tag.of("uri", "/test"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void shouldNotAddPathValueWhenDisabled() {
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> factory = mock(ReactiveLoadBalancer.Factory.class);
|
||||
@@ -102,7 +104,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
MicrometerStatsLoadBalancerLifecycle statsLifecycle = new MicrometerStatsLoadBalancerLifecycle(meterRegistry,
|
||||
factory);
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
new LinkedMultiValueMap<>(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
Response<ServiceInstance> lbResponse = new DefaultResponse(
|
||||
new DefaultServiceInstance("test-1", "test", "test.org", 8080, false, new HashMap<>()));
|
||||
@@ -126,7 +128,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
String uriTemplate = "/test/{pathParam}/test";
|
||||
attributes.put(attributeName, uriTemplate);
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test/123/test"),
|
||||
new HttpHeaders(), new HttpHeaders(), attributes);
|
||||
new HttpHeaders(), new LinkedMultiValueMap<>(), attributes);
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
Response<ServiceInstance> lbResponse = new DefaultResponse(
|
||||
new DefaultServiceInstance("test-1", "test", "test.org", 8080, false, new HashMap<>()));
|
||||
@@ -152,7 +154,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
@Test
|
||||
void shouldRecordFailedTimedRequest() {
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
new LinkedMultiValueMap<>(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
Response<ServiceInstance> lbResponse = new DefaultResponse(
|
||||
new DefaultServiceInstance("test-1", "test", "test.org", 8080, false, new HashMap<>()));
|
||||
@@ -175,7 +177,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
@Test
|
||||
void shouldNotRecordDiscardedRequest() {
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
new LinkedMultiValueMap<>(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
Response<ServiceInstance> lbResponse = new EmptyResponse();
|
||||
statsLifecycle.onStartRequest(lbRequest, lbResponse);
|
||||
@@ -247,7 +249,7 @@ class MicrometerStatsLoadBalancerLifecycleTests {
|
||||
@Test
|
||||
void shouldHandleNullLoadBalancerResponse() {
|
||||
RequestData requestData = new RequestData(HttpMethod.GET, URI.create("http://test.org/test"), new HttpHeaders(),
|
||||
new HttpHeaders(), new HashMap<>());
|
||||
new LinkedMultiValueMap<>(), new HashMap<>());
|
||||
Request<Object> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData));
|
||||
assertThatCode(() -> {
|
||||
statsLifecycle.onStartRequest(lbRequest, null);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter</artifactId>
|
||||
<name>spring-cloud-starter</name>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>4.3.1-SNAPSHOT</version>
|
||||
<version>5.0.0-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user