Adds config per load balancer client. (#1028)
Client specific configuration goes under `spring.cloud.loadbalancer.clients.<serviceId>.*`. Defaults are set using `spring.cloud.loadbalancer.*`.
Adds LoadBalancerDefaultMappingsProviderAutoConfiguration to supply the loadbalancer defaults mapping to DefaultsBindHandlerAdvisor
LoadBalancerClientsProperties now extends LoadBalancerProperties. The `clients` attribute is now a field. The `@ConfigurationProperties("spring.cloud.loadbalancer")` has moved from LoadBalancerProperties to LoadBalancerClientsProperties
Fixes gh-914
This commit is contained in:
@@ -468,6 +468,8 @@ For the reactive implementation, you can additionally set:
|
||||
|
||||
For the reactive implementation, you can also implement your own `LoadBalancerRetryPolicy` to have more detailed control over the load-balanced call retries.
|
||||
|
||||
NOTE: Individual Loadbalancer clients may be configured individually with the same properties as above except the prefix is `spring.cloud.loadbalancer.clients.<clientId>.*` where `clientId` is the name of the loadbalancer.
|
||||
|
||||
NOTE: For load-balanced retries, by default, we wrap the `ServiceInstanceListSupplier` bean with `RetryAwareServiceInstanceListSupplier` to select a different instance from the one previously chosen, if available. You can disable this behavior by setting the value of `spring.cloud.loadbalancer.retry.avoidPreviousInstance` to `false`.
|
||||
|
||||
====
|
||||
@@ -1246,6 +1248,27 @@ NOTE: The meters are registered in the registry when at least one record is adde
|
||||
|
||||
TIP: You can further configure the behavior of those metrics (for example, add https://micrometer.io/docs/concepts#_histograms_and_percentiles[publishing percentiles and histograms]) by https://docs.spring.io/spring-boot/docs/current/reference/html/production-ready-features.html#production-ready-metrics-per-meter-properties[adding `MeterFilters`].
|
||||
|
||||
=== Configuring Individual LoadBalancerClients
|
||||
|
||||
Individual Loadbalancer clients may be configured individually with a different prefix `spring.cloud.loadbalancer.clients.<clientId>.*` where `clientId` is the name of the loadbalancer. Default configuration values may be set in the `spring.cloud.loadbalancer.*` namespace and will be merged with the client specific values taking precedence
|
||||
|
||||
.application.yml
|
||||
====
|
||||
----
|
||||
spring:
|
||||
cloud:
|
||||
loadbalancer:
|
||||
health-check:
|
||||
initial-delay: 1s
|
||||
clients:
|
||||
myclient:
|
||||
health-check:
|
||||
interval: 30s
|
||||
----
|
||||
====
|
||||
|
||||
The above example will result in a merged health-check `@ConfigurationProperties` object with `initial-delay=1s` and `interval=30s`.
|
||||
|
||||
== Spring Cloud Circuit Breaker
|
||||
|
||||
include::spring-cloud-circuitbreaker.adoc[leveloffset=+1]
|
||||
|
||||
@@ -51,7 +51,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RestTemplate.class)
|
||||
@ConditionalOnBean(LoadBalancerClient.class)
|
||||
@EnableConfigurationProperties(LoadBalancerProperties.class)
|
||||
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
|
||||
public class LoadBalancerAutoConfiguration {
|
||||
|
||||
@LoadBalanced
|
||||
@@ -147,11 +147,10 @@ public class LoadBalancerAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RetryLoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,
|
||||
LoadBalancerProperties properties, LoadBalancerRequestFactory requestFactory,
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory,
|
||||
LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, requestFactory,
|
||||
loadBalancedRetryFactory, loadBalancerFactory);
|
||||
return new RetryLoadBalancerInterceptor(loadBalancerClient, requestFactory, loadBalancedRetryFactory,
|
||||
loadBalancerFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* A {@link ConfigurationProperties} bean for Spring Cloud Loadbalancer.
|
||||
*
|
||||
* Individual clients are configured via the {@link LoadBalancerClientsProperties#clients}
|
||||
* field. Defaults and other properties are located in the {@link LoadBalancerProperties}
|
||||
* base class.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.loadbalancer")
|
||||
public class LoadBalancerClientsProperties extends LoadBalancerProperties {
|
||||
|
||||
private Map<String, LoadBalancerProperties> clients = new HashMap<>();
|
||||
|
||||
public Map<String, LoadBalancerProperties> getClients() {
|
||||
return this.clients;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2012-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.client.loadbalancer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
import org.springframework.cloud.commons.config.DefaultsBindHandlerAdvisor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@AutoConfigureBefore(name = "org.springframework.cloud.commons.config.CommonsConfigAutoConfiguration")
|
||||
public class LoadBalancerDefaultMappingsProviderAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public DefaultsBindHandlerAdvisor.MappingsProvider loadBalancerClientsDefaultsMappingsProvider() {
|
||||
return () -> {
|
||||
Map<ConfigurationPropertyName, ConfigurationPropertyName> mappings = new HashMap<>();
|
||||
mappings.put(ConfigurationPropertyName.of("spring.cloud.loadbalancer.clients"),
|
||||
ConfigurationPropertyName.of("spring.cloud.loadbalancer"));
|
||||
return mappings;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,12 +29,14 @@ import org.springframework.http.HttpMethod;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
* A {@link ConfigurationProperties} bean for Spring Cloud LoadBalancer.
|
||||
* The base configuration bean for Spring Cloud LoadBalancer.
|
||||
*
|
||||
* See {@link LoadBalancerClientsProperties} for the {@link ConfigurationProperties}
|
||||
* annotation.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 2.2.1
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.loadbalancer")
|
||||
public class LoadBalancerProperties {
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.cloud.client.loadbalancer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -50,19 +51,26 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
|
||||
|
||||
private final LoadBalancerClient loadBalancer;
|
||||
|
||||
private final LoadBalancerProperties properties;
|
||||
|
||||
private final LoadBalancerRequestFactory requestFactory;
|
||||
|
||||
private final LoadBalancedRetryFactory lbRetryFactory;
|
||||
|
||||
private final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory;
|
||||
|
||||
@Deprecated
|
||||
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerProperties properties,
|
||||
LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory lbRetryFactory,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
this.loadBalancer = loadBalancer;
|
||||
this.properties = properties;
|
||||
this.requestFactory = requestFactory;
|
||||
this.lbRetryFactory = lbRetryFactory;
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
}
|
||||
|
||||
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory,
|
||||
LoadBalancedRetryFactory lbRetryFactory,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
this.loadBalancer = loadBalancer;
|
||||
this.requestFactory = requestFactory;
|
||||
this.lbRetryFactory = lbRetryFactory;
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
@@ -159,14 +167,17 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
|
||||
if (retryListeners != null && retryListeners.length != 0) {
|
||||
template.setListeners(retryListeners);
|
||||
}
|
||||
template.setRetryPolicy(!properties.getRetry().isEnabled() || retryPolicy == null ? new NeverRetryPolicy()
|
||||
: new InterceptorRetryPolicy(request, retryPolicy, loadBalancer, serviceName));
|
||||
template.setRetryPolicy(
|
||||
!loadBalancerFactory.getProperties(serviceName).getRetry().isEnabled() || retryPolicy == null
|
||||
? new NeverRetryPolicy()
|
||||
: new InterceptorRetryPolicy(request, retryPolicy, loadBalancer, serviceName));
|
||||
return template;
|
||||
}
|
||||
|
||||
private String getHint(String serviceId) {
|
||||
String defaultHint = properties.getHint().getOrDefault("default", "default");
|
||||
String hintPropertyValue = properties.getHint().get(serviceId);
|
||||
Map<String, String> hint = loadBalancerFactory.getProperties(serviceId).getHint();
|
||||
String defaultHint = hint.getOrDefault("default", "default");
|
||||
String hintPropertyValue = hint.get(serviceId);
|
||||
return hintPropertyValue != null ? hintPropertyValue : defaultHint;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.client.loadbalancer.reactive;
|
||||
|
||||
import org.springframework.cglib.core.internal.Function;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
/**
|
||||
@@ -55,4 +56,8 @@ public interface LoadBalancerRetryPolicy {
|
||||
*/
|
||||
boolean canRetryOnMethod(HttpMethod method);
|
||||
|
||||
interface Factory extends Function<String, LoadBalancerRetryPolicy> {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
|
||||
import org.springframework.cloud.client.loadbalancer.DefaultRequestContext;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.Request;
|
||||
import org.springframework.cloud.client.loadbalancer.Response;
|
||||
|
||||
@@ -53,6 +54,10 @@ public interface ReactiveLoadBalancer<T> {
|
||||
|
||||
interface Factory<T> {
|
||||
|
||||
default LoadBalancerProperties getProperties(String serviceId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ReactiveLoadBalancer<T> getInstance(String serviceId);
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,9 +24,10 @@ 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.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
@@ -42,6 +43,7 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
@ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
|
||||
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
|
||||
public class ReactorLoadBalancerClientAutoConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@@ -49,9 +51,9 @@ public class ReactorLoadBalancerClientAutoConfiguration {
|
||||
matchIfMissing = true)
|
||||
@Bean
|
||||
public ReactorLoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory, LoadBalancerProperties properties,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
|
||||
ObjectProvider<List<LoadBalancerClientRequestTransformer>> transformers) {
|
||||
return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory, properties,
|
||||
return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory,
|
||||
transformers.getIfAvailable(Collections::emptyList));
|
||||
}
|
||||
|
||||
@@ -59,18 +61,19 @@ public class ReactorLoadBalancerClientAutoConfiguration {
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true")
|
||||
@Bean
|
||||
public RetryableLoadBalancerExchangeFilterFunction retryableLoadBalancerExchangeFilterFunction(
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory, LoadBalancerProperties properties,
|
||||
LoadBalancerRetryPolicy retryPolicy,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
|
||||
LoadBalancerRetryPolicy.Factory retryPolicyFactory,
|
||||
ObjectProvider<List<LoadBalancerClientRequestTransformer>> transformers) {
|
||||
return new RetryableLoadBalancerExchangeFilterFunction(retryPolicy, loadBalancerFactory, properties,
|
||||
return new RetryableLoadBalancerExchangeFilterFunction(retryPolicyFactory, loadBalancerFactory,
|
||||
transformers.getIfAvailable(Collections::emptyList));
|
||||
}
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "true")
|
||||
@Bean
|
||||
public LoadBalancerRetryPolicy loadBalancerRetryPolicy(LoadBalancerProperties properties) {
|
||||
return new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy(properties);
|
||||
public LoadBalancerRetryPolicy.Factory loadBalancerRetryPolicy(
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
return new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy.Factory(loadBalancerFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,8 +61,6 @@ public class ReactorLoadBalancerExchangeFilterFunction implements LoadBalancedEx
|
||||
|
||||
private final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory;
|
||||
|
||||
private final LoadBalancerProperties properties;
|
||||
|
||||
private final List<LoadBalancerClientRequestTransformer> transformers;
|
||||
|
||||
/**
|
||||
@@ -77,10 +75,16 @@ public class ReactorLoadBalancerExchangeFilterFunction implements LoadBalancedEx
|
||||
this(loadBalancerFactory, properties, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ReactorLoadBalancerExchangeFilterFunction(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
|
||||
LoadBalancerProperties properties, List<LoadBalancerClientRequestTransformer> transformers) {
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
this.properties = properties;
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
public ReactorLoadBalancerExchangeFilterFunction(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
|
||||
List<LoadBalancerClientRequestTransformer> transformers) {
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
@@ -99,7 +103,7 @@ public class ReactorLoadBalancerExchangeFilterFunction implements LoadBalancedEx
|
||||
.getSupportedLifecycleProcessors(
|
||||
loadBalancerFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
|
||||
RequestDataContext.class, ResponseData.class, ServiceInstance.class);
|
||||
String hint = getHint(serviceId, properties.getHint());
|
||||
String hint = getHint(serviceId, loadBalancerFactory.getProperties(serviceId).getHint());
|
||||
RequestData requestData = new RequestData(clientRequest);
|
||||
DefaultRequest<RequestDataContext> lbRequest = new DefaultRequest<>(new RequestDataContext(requestData, hint));
|
||||
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStart(lbRequest));
|
||||
@@ -120,7 +124,8 @@ public class ReactorLoadBalancerExchangeFilterFunction implements LoadBalancedEx
|
||||
LOG.debug(String.format("LoadBalancer has retrieved the instance for service %s: %s", serviceId,
|
||||
instance.getUri()));
|
||||
}
|
||||
LoadBalancerProperties.StickySession stickySessionProperties = properties.getStickySession();
|
||||
LoadBalancerProperties.StickySession stickySessionProperties = loadBalancerFactory.getProperties(serviceId)
|
||||
.getStickySession();
|
||||
ClientRequest newRequest = buildClientRequest(clientRequest, instance,
|
||||
stickySessionProperties.getInstanceIdCookieName(),
|
||||
stickySessionProperties.isAddServiceInstanceCookie(), transformers);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.cloud.client.loadbalancer.reactive;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
@@ -53,4 +54,20 @@ public class RetryableExchangeFilterFunctionLoadBalancerRetryPolicy implements L
|
||||
return HttpMethod.GET.equals(method) || properties.getRetry().isRetryOnAllOperations();
|
||||
}
|
||||
|
||||
static class Factory implements LoadBalancerRetryPolicy.Factory {
|
||||
|
||||
final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory;
|
||||
|
||||
Factory(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadBalancerRetryPolicy apply(String serviceId) {
|
||||
return new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy(
|
||||
loadBalancerFactory.getProperties(serviceId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,9 +69,7 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
private static final List<Class<? extends Throwable>> exceptions = Arrays.asList(IOException.class,
|
||||
TimeoutException.class, RetryableStatusCodeException.class);
|
||||
|
||||
private final LoadBalancerRetryPolicy retryPolicy;
|
||||
|
||||
private final LoadBalancerProperties properties;
|
||||
private final LoadBalancerRetryPolicy.Factory retryPolicyFactory;
|
||||
|
||||
private final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory;
|
||||
|
||||
@@ -87,22 +85,26 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
this(retryPolicy, loadBalancerFactory, properties, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public RetryableLoadBalancerExchangeFilterFunction(LoadBalancerRetryPolicy retryPolicy,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory, LoadBalancerProperties properties,
|
||||
List<LoadBalancerClientRequestTransformer> transformers) {
|
||||
this.retryPolicy = retryPolicy;
|
||||
this.retryPolicyFactory = s -> retryPolicy;
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
public RetryableLoadBalancerExchangeFilterFunction(LoadBalancerRetryPolicy.Factory retryPolicyFactory,
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory,
|
||||
List<LoadBalancerClientRequestTransformer> transformers) {
|
||||
this.retryPolicyFactory = retryPolicyFactory;
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
this.properties = properties;
|
||||
this.transformers = transformers;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@Override
|
||||
public Mono<ClientResponse> filter(ClientRequest clientRequest, ExchangeFunction next) {
|
||||
LoadBalancerRetryContext loadBalancerRetryContext = new LoadBalancerRetryContext(clientRequest);
|
||||
Retry exchangeRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnSameServiceInstance(), true);
|
||||
Retry filterRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnNextServiceInstance(), false);
|
||||
|
||||
URI originalUrl = clientRequest.url();
|
||||
String serviceId = originalUrl.getHost();
|
||||
if (serviceId == null) {
|
||||
@@ -112,6 +114,15 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
}
|
||||
return Mono.just(ClientResponse.create(HttpStatus.BAD_REQUEST).body(message).build());
|
||||
}
|
||||
LoadBalancerRetryContext loadBalancerRetryContext = new LoadBalancerRetryContext(clientRequest);
|
||||
LoadBalancerProperties properties = loadBalancerFactory.getProperties(serviceId);
|
||||
|
||||
Retry exchangeRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnSameServiceInstance(), true,
|
||||
properties.getRetry());
|
||||
Retry filterRetry = buildRetrySpec(properties.getRetry().getMaxRetriesOnNextServiceInstance(), false,
|
||||
properties.getRetry());
|
||||
LoadBalancerRetryPolicy retryPolicy = retryPolicyFactory.apply(serviceId);
|
||||
|
||||
Set<LoadBalancerLifecycle> supportedLifecycleProcessors = LoadBalancerLifecycleValidator
|
||||
.getSupportedLifecycleProcessors(
|
||||
loadBalancerFactory.getInstances(serviceId, LoadBalancerLifecycle.class),
|
||||
@@ -154,7 +165,7 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
lbRequest, lbResponse, new ResponseData(clientResponse, requestData)))))
|
||||
.map(clientResponse -> {
|
||||
loadBalancerRetryContext.setClientResponse(clientResponse);
|
||||
if (shouldRetrySameServiceInstance(loadBalancerRetryContext)) {
|
||||
if (shouldRetrySameServiceInstance(retryPolicy, loadBalancerRetryContext)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Retrying on status code: %d",
|
||||
clientResponse.statusCode().value()));
|
||||
@@ -166,7 +177,7 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
});
|
||||
}).map(clientResponse -> {
|
||||
loadBalancerRetryContext.setClientResponse(clientResponse);
|
||||
if (shouldRetryNextServiceInstance(loadBalancerRetryContext)) {
|
||||
if (shouldRetryNextServiceInstance(retryPolicy, loadBalancerRetryContext)) {
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug(String.format("Retrying on status code: %d", clientResponse.statusCode().value()));
|
||||
}
|
||||
@@ -177,8 +188,11 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
}).retryWhen(exchangeRetry)).retryWhen(filterRetry);
|
||||
}
|
||||
|
||||
private Retry buildRetrySpec(int max, boolean transientErrors) {
|
||||
LoadBalancerProperties.Retry.Backoff backoffProperties = properties.getRetry().getBackoff();
|
||||
private Retry buildRetrySpec(int max, boolean transientErrors, LoadBalancerProperties.Retry retry) {
|
||||
if (!retry.isEnabled()) {
|
||||
return Retry.max(0).filter(this::isRetryException).transientErrors(transientErrors);
|
||||
}
|
||||
LoadBalancerProperties.Retry.Backoff backoffProperties = retry.getBackoff();
|
||||
if (backoffProperties.isEnabled()) {
|
||||
return RetrySpec.backoff(max, backoffProperties.getMinBackoff()).filter(this::isRetryException)
|
||||
.maxBackoff(backoffProperties.getMaxBackoff()).jitter(backoffProperties.getJitter())
|
||||
@@ -187,7 +201,8 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
return RetrySpec.max(max).filter(this::isRetryException).transientErrors(transientErrors);
|
||||
}
|
||||
|
||||
private boolean shouldRetrySameServiceInstance(LoadBalancerRetryContext loadBalancerRetryContext) {
|
||||
private boolean shouldRetrySameServiceInstance(LoadBalancerRetryPolicy retryPolicy,
|
||||
LoadBalancerRetryContext loadBalancerRetryContext) {
|
||||
boolean shouldRetry = retryPolicy.retryableStatusCode(loadBalancerRetryContext.getResponseStatusCode())
|
||||
&& retryPolicy.canRetryOnMethod(loadBalancerRetryContext.getRequestMethod())
|
||||
&& retryPolicy.canRetrySameServiceInstance(loadBalancerRetryContext);
|
||||
@@ -197,7 +212,8 @@ public class RetryableLoadBalancerExchangeFilterFunction implements LoadBalanced
|
||||
return shouldRetry;
|
||||
}
|
||||
|
||||
private boolean shouldRetryNextServiceInstance(LoadBalancerRetryContext loadBalancerRetryContext) {
|
||||
private boolean shouldRetryNextServiceInstance(LoadBalancerRetryPolicy retryPolicy,
|
||||
LoadBalancerRetryContext loadBalancerRetryContext) {
|
||||
boolean shouldRetry = retryPolicy.retryableStatusCode(loadBalancerRetryContext.getResponseStatusCode())
|
||||
&& retryPolicy.canRetryOnMethod(loadBalancerRetryContext.getRequestMethod())
|
||||
&& retryPolicy.canRetryNextServiceInstance(loadBalancerRetryContext);
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.springframework.core.env.PropertySource;
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
// TODO: 4.0.0 move to org.springframework.cloud.commons.config
|
||||
public abstract class ConfigDataMissingEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 2012-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.commons.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
* @since 3.1.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class CommonsConfigAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public DefaultsBindHandlerAdvisor defaultsBindHandlerAdvisor(
|
||||
@Nullable DefaultsBindHandlerAdvisor.MappingsProvider[] providers) {
|
||||
Map<ConfigurationPropertyName, ConfigurationPropertyName> additionalMappings = new HashMap<>();
|
||||
if (!ObjectUtils.isEmpty(providers)) {
|
||||
for (int i = 0; i < providers.length; i++) {
|
||||
DefaultsBindHandlerAdvisor.MappingsProvider mappingsProvider = providers[i];
|
||||
additionalMappings.putAll(mappingsProvider.getDefaultMappings());
|
||||
}
|
||||
}
|
||||
return new DefaultsBindHandlerAdvisor(additionalMappings);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2013-2021 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.commons.config;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationPropertiesBindHandlerAdvisor;
|
||||
import org.springframework.boot.context.properties.bind.AbstractBindHandler;
|
||||
import org.springframework.boot.context.properties.bind.BindContext;
|
||||
import org.springframework.boot.context.properties.bind.BindHandler;
|
||||
import org.springframework.boot.context.properties.bind.BindResult;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName;
|
||||
import org.springframework.boot.context.properties.source.ConfigurationPropertyName.Form;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
/**
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 3.1.0
|
||||
*/
|
||||
public class DefaultsBindHandlerAdvisor implements ConfigurationPropertiesBindHandlerAdvisor {
|
||||
|
||||
private final Map<ConfigurationPropertyName, ConfigurationPropertyName> mappings;
|
||||
|
||||
public DefaultsBindHandlerAdvisor(Map<ConfigurationPropertyName, ConfigurationPropertyName> additionalMappings) {
|
||||
this.mappings = new LinkedHashMap<>();
|
||||
if (!CollectionUtils.isEmpty(additionalMappings)) {
|
||||
this.mappings.putAll(additionalMappings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BindHandler apply(BindHandler bindHandler) {
|
||||
|
||||
BindHandler handler = new AbstractBindHandler(bindHandler) {
|
||||
@Override
|
||||
public <T> Bindable<T> onStart(ConfigurationPropertyName name, Bindable<T> target, BindContext context) {
|
||||
ConfigurationPropertyName defaultName = getDefaultName(name);
|
||||
if (defaultName != null) {
|
||||
BindResult<T> result = context.getBinder().bind(defaultName, target);
|
||||
if (result.isBound()) {
|
||||
return target.withExistingValue(result.get());
|
||||
}
|
||||
}
|
||||
return bindHandler.onStart(name, target, context);
|
||||
}
|
||||
};
|
||||
return handler;
|
||||
}
|
||||
|
||||
private ConfigurationPropertyName getDefaultName(ConfigurationPropertyName name) {
|
||||
for (Map.Entry<ConfigurationPropertyName, ConfigurationPropertyName> mapping : this.mappings.entrySet()) {
|
||||
ConfigurationPropertyName from = mapping.getKey();
|
||||
ConfigurationPropertyName to = mapping.getValue();
|
||||
if ((from.isAncestorOf(name) && name.getNumberOfElements() > from.getNumberOfElements())) {
|
||||
ConfigurationPropertyName defaultName = to;
|
||||
for (int i = from.getNumberOfElements() + 1; i < name.getNumberOfElements(); i++) {
|
||||
defaultName = defaultName.append(name.getElement(i, Form.UNIFORM));
|
||||
}
|
||||
return defaultName;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides mappings including the default mappings.
|
||||
*/
|
||||
public interface MappingsProvider {
|
||||
|
||||
Map<ConfigurationPropertyName, ConfigurationPropertyName> getDefaultMappings();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@ org.springframework.cloud.client.discovery.simple.reactive.SimpleReactiveDiscove
|
||||
org.springframework.cloud.client.hypermedia.CloudHypermediaAutoConfiguration,\
|
||||
org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration,\
|
||||
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration,\
|
||||
org.springframework.cloud.client.loadbalancer.LoadBalancerDefaultMappingsProviderAutoConfiguration,\
|
||||
org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration,\
|
||||
org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerClientAutoConfiguration,\
|
||||
org.springframework.cloud.client.serviceregistry.ServiceRegistryAutoConfiguration,\
|
||||
@@ -16,7 +17,8 @@ org.springframework.cloud.commons.httpclient.HttpClientConfiguration,\
|
||||
org.springframework.cloud.commons.util.UtilAutoConfiguration,\
|
||||
org.springframework.cloud.configuration.CompatibilityVerifierAutoConfiguration,\
|
||||
org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration,\
|
||||
org.springframework.cloud.commons.security.ResourceServerTokenRelayAutoConfiguration
|
||||
org.springframework.cloud.commons.security.ResourceServerTokenRelayAutoConfiguration,\
|
||||
org.springframework.cloud.commons.config.CommonsConfigAutoConfiguration
|
||||
# Environment Post Processors
|
||||
org.springframework.boot.env.EnvironmentPostProcessor=\
|
||||
org.springframework.cloud.client.HostInfoEnvironmentPostProcessor
|
||||
|
||||
@@ -103,8 +103,8 @@ public abstract class AbstractLoadBalancerAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory() {
|
||||
return new TestLoadBalancerFactory();
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory(LoadBalancerProperties properties) {
|
||||
return new TestLoadBalancerFactory(properties);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -176,6 +176,12 @@ public abstract class AbstractLoadBalancerAutoConfigurationTests {
|
||||
|
||||
private static class TestLoadBalancerFactory implements ReactiveLoadBalancer.Factory<ServiceInstance> {
|
||||
|
||||
private final LoadBalancerProperties properties;
|
||||
|
||||
TestLoadBalancerFactory(LoadBalancerProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
|
||||
throw new UnsupportedOperationException("Not implemented.");
|
||||
@@ -191,6 +197,11 @@ public abstract class AbstractLoadBalancerAutoConfigurationTests {
|
||||
throw new UnsupportedOperationException("Not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadBalancerProperties getProperties(String serviceId) {
|
||||
return properties;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
/**
|
||||
* @author Ryan Baxter
|
||||
@@ -88,7 +89,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
client = mock(LoadBalancerClient.class);
|
||||
lbRequestFactory = mock(LoadBalancerRequestFactory.class);
|
||||
properties = new LoadBalancerProperties();
|
||||
lbFactory = mock(ReactiveLoadBalancer.Factory.class);
|
||||
lbFactory = mock(ReactiveLoadBalancer.Factory.class, withSettings().lenient());
|
||||
when(lbFactory.getProperties(any())).thenReturn(properties);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
@@ -105,8 +107,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class)))
|
||||
.thenThrow(new IOException());
|
||||
properties.getRetry().setEnabled(false);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, loadBalancedRetryFactory, lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
loadBalancedRetryFactory, lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
|
||||
@@ -123,8 +125,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
HttpRequest request = mock(HttpRequest.class);
|
||||
when(request.getURI()).thenReturn(new URI("http://foo_underscore"));
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, loadBalancedRetryFactory, lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
loadBalancedRetryFactory, lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
Assertions.assertThrows(IllegalStateException.class, () -> {
|
||||
@@ -143,8 +145,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
.thenReturn(clientHttpResponse);
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, loadBalancedRetryFactory, lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
loadBalancedRetryFactory, lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
interceptor.intercept(request, body, execution);
|
||||
@@ -163,8 +165,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
.thenReturn(clientHttpResponse);
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -189,8 +191,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), nullable(LoadBalancerRequest.class)))
|
||||
.thenReturn(clientHttpResponseNotFound).thenReturn(clientHttpResponseOk);
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -222,8 +224,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
properties.getRetry().setEnabled(true);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
|
||||
verify(client, times(1)).execute(eq("foo"), eq(serviceInstance),
|
||||
@@ -252,8 +254,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
.thenThrow(new IOException()).thenReturn(clientHttpResponse);
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy, backOffPolicy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy, backOffPolicy), lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -276,8 +278,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
.thenThrow(new IOException()).thenReturn(clientHttpResponse);
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
properties.getRetry().setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy), lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
Assertions.assertThrows(IOException.class, () -> {
|
||||
@@ -305,8 +307,7 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
properties.getRetry().setEnabled(true);
|
||||
MyRetryListener retryListener = new MyRetryListener();
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory,
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy, backOffPolicy, new RetryListener[] { retryListener }),
|
||||
lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
@@ -333,8 +334,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
.thenThrow(new IOException()).thenReturn(clientHttpResponse);
|
||||
properties.getRetry().setEnabled(true);
|
||||
when(lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, new MyLoadBalancedRetryFactory(policy, backOffPolicy), lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy, backOffPolicy), lbFactory);
|
||||
byte[] body = new byte[] {};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -357,8 +358,7 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory,
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
new MyLoadBalancedRetryFactory(policy, backOffPolicy, new RetryListener[] { myRetryListener }),
|
||||
lbFactory);
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
@@ -376,8 +376,8 @@ public class RetryLoadBalancerInterceptorTests {
|
||||
HttpRequest request = mock(HttpRequest.class);
|
||||
when(request.getURI()).thenReturn(new URI("http://test"));
|
||||
TestLoadBalancerClient client = new TestLoadBalancerClient();
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, properties,
|
||||
lbRequestFactory, loadBalancedRetryFactory, lbFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbRequestFactory,
|
||||
loadBalancedRetryFactory, lbFactory);
|
||||
|
||||
interceptor.intercept(request, new byte[] {}, mock(ClientHttpRequestExecution.class));
|
||||
|
||||
|
||||
@@ -63,6 +63,7 @@ class LoadBalancerClientRequestTransformerTest {
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
when(factory.getInstance("testServiceId")).thenReturn(new TestReactiveLoadBalancer());
|
||||
when(factory.getProperties(any())).thenReturn(properties);
|
||||
when(clientRequest.method()).thenReturn(HttpMethod.GET);
|
||||
when(clientRequest.url()).thenReturn(URI.create("http://testServiceId"));
|
||||
when(clientRequest.headers()).thenReturn(new HttpHeaders());
|
||||
@@ -75,7 +76,7 @@ class LoadBalancerClientRequestTransformerTest {
|
||||
void transformReactorLoadBalancerExchangeFilterFunction() {
|
||||
ArgumentCaptor<ClientRequest> captor = ArgumentCaptor.forClass(ClientRequest.class);
|
||||
ReactorLoadBalancerExchangeFilterFunction filterFunction = new ReactorLoadBalancerExchangeFilterFunction(
|
||||
factory, properties, Arrays.asList(new Transformer1(), new Transformer2()));
|
||||
factory, Arrays.asList(new Transformer1(), new Transformer2()));
|
||||
filterFunction.filter(clientRequest, next).subscribe();
|
||||
verify(next).exchange(captor.capture());
|
||||
HttpHeaders headers = captor.getValue().headers();
|
||||
@@ -87,7 +88,7 @@ class LoadBalancerClientRequestTransformerTest {
|
||||
void transformRetryableLoadBalancerExchangeFilterFunction() {
|
||||
ArgumentCaptor<ClientRequest> captor = ArgumentCaptor.forClass(ClientRequest.class);
|
||||
RetryableLoadBalancerExchangeFilterFunction filterFunction = new RetryableLoadBalancerExchangeFilterFunction(
|
||||
policy, factory, properties, Arrays.asList(new Transformer1(), new Transformer2()));
|
||||
s -> policy, factory, Arrays.asList(new Transformer1(), new Transformer2()));
|
||||
filterFunction.filter(clientRequest, next).subscribe();
|
||||
verify(next).exchange(captor.capture());
|
||||
HttpHeaders headers = captor.getValue().headers();
|
||||
|
||||
@@ -16,14 +16,19 @@
|
||||
|
||||
package org.springframework.cloud.client.loadbalancer.reactive;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
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.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -128,16 +133,39 @@ public class ReactorLoadBalancerClientAutoConfigurationTests {
|
||||
then(getFilters(builder)).isNullOrEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultPropertiesWorks() {
|
||||
ConfigurableApplicationContext context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
|
||||
.sources(OneWebClientBuilder.class, DefaulConfig.class)
|
||||
.properties("spring.cloud.loadbalancer.health-check.initial-delay=1s",
|
||||
"spring.cloud.loadbalancer.clients.myclient.health-check.interval=30s")
|
||||
.run();
|
||||
LoadBalancerClientsProperties properties = context.getBean(LoadBalancerClientsProperties.class);
|
||||
|
||||
then(properties.getClients()).containsKey("myclient");
|
||||
LoadBalancerProperties clientProperties = properties.getClients().get("myclient");
|
||||
// default value
|
||||
then(clientProperties.getHealthCheck().getInitialDelay()).isEqualTo(Duration.ofSeconds(1));
|
||||
// client specific value
|
||||
then(clientProperties.getHealthCheck().getInterval()).isEqualTo(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext init(Class<?> config) {
|
||||
return LoadBalancerTestUtils.init(config, ReactorLoadBalancerClientAutoConfiguration.class,
|
||||
LoadBalancerBeanPostProcessorAutoConfiguration.class);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
protected static class DefaulConfig {
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class NoWebClientBuilder {
|
||||
|
||||
@Bean
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory() {
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(LoadBalancerProperties properties) {
|
||||
return new ReactiveLoadBalancer.Factory<ServiceInstance>() {
|
||||
@Override
|
||||
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
|
||||
@@ -153,6 +181,11 @@ public class ReactorLoadBalancerClientAutoConfigurationTests {
|
||||
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
|
||||
throw new UnsupportedOperationException("Not implemented.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadBalancerProperties getProperties(String serviceId) {
|
||||
return properties;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -162,11 +195,6 @@ public class ReactorLoadBalancerClientAutoConfigurationTests {
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
LoadBalancerProperties loadBalancerProperties() {
|
||||
return new LoadBalancerProperties();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -171,7 +171,8 @@ class ReactorLoadBalancerExchangeFilterFunctionTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(DiscoveryClient discoveryClient) {
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(DiscoveryClient discoveryClient,
|
||||
LoadBalancerProperties properties) {
|
||||
return new ReactiveLoadBalancer.Factory<ServiceInstance>() {
|
||||
|
||||
private final TestLoadBalancerLifecycle testLoadBalancerLifecycle = new TestLoadBalancerLifecycle();
|
||||
@@ -198,12 +199,12 @@ class ReactorLoadBalancerExchangeFilterFunctionTests {
|
||||
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
LoadBalancerProperties loadBalancerProperties() {
|
||||
return new LoadBalancerProperties();
|
||||
@Override
|
||||
public LoadBalancerProperties getProperties(String serviceId) {
|
||||
return properties;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -228,7 +228,8 @@ class RetryableLoadBalancerExchangeFilterFunctionIntegrationTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(DiscoveryClient discoveryClient) {
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> reactiveLoadBalancerFactory(DiscoveryClient discoveryClient,
|
||||
LoadBalancerProperties properties) {
|
||||
return new ReactiveLoadBalancer.Factory<ServiceInstance>() {
|
||||
|
||||
private final TestLoadBalancerLifecycle testLoadBalancerLifecycle = new TestLoadBalancerLifecycle();
|
||||
@@ -256,12 +257,12 @@ class RetryableLoadBalancerExchangeFilterFunctionIntegrationTests {
|
||||
public <X> X getInstance(String name, Class<?> clazz, Class<?>... generics) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
LoadBalancerProperties loadBalancerProperties() {
|
||||
return new LoadBalancerProperties();
|
||||
@Override
|
||||
public LoadBalancerProperties getProperties(String serviceId) {
|
||||
return properties;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -74,6 +74,7 @@ class RetryableLoadBalancerExchangeFilterFunctionTests {
|
||||
properties.getRetry().getRetryableStatusCodes().add(404);
|
||||
when(clientRequest.url()).thenReturn(URI.create("http://test"));
|
||||
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());
|
||||
|
||||
@@ -138,7 +139,7 @@ class RetryableLoadBalancerExchangeFilterFunctionTests {
|
||||
properties.getRetry().getRetryableStatusCodes().add(404);
|
||||
LoadBalancerRetryPolicy policy = new RetryableExchangeFilterFunctionLoadBalancerRetryPolicy(properties);
|
||||
RetryableLoadBalancerExchangeFilterFunction filterFunction = new RetryableLoadBalancerExchangeFilterFunction(
|
||||
policy, factory, properties, Collections.emptyList());
|
||||
s -> policy, factory, Collections.emptyList());
|
||||
when(clientRequest.method()).thenReturn(HttpMethod.POST);
|
||||
when(clientResponse.statusCode()).thenReturn(HttpStatus.NOT_FOUND);
|
||||
when(next.exchange(any())).thenReturn(Mono.just(clientResponse));
|
||||
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
package org.springframework.cloud.loadbalancer.blocking.retry;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.ServiceInstanceChooser;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
|
||||
/**
|
||||
@@ -31,15 +32,15 @@ import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalanc
|
||||
*/
|
||||
public class BlockingLoadBalancedRetryFactory implements LoadBalancedRetryFactory {
|
||||
|
||||
private final LoadBalancerProperties loadBalancerProperties;
|
||||
private final ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory;
|
||||
|
||||
public BlockingLoadBalancedRetryFactory(LoadBalancerProperties loadBalancerProperties) {
|
||||
this.loadBalancerProperties = loadBalancerProperties;
|
||||
public BlockingLoadBalancedRetryFactory(ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
this.loadBalancerFactory = loadBalancerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadBalancedRetryPolicy createRetryPolicy(String serviceId, ServiceInstanceChooser serviceInstanceChooser) {
|
||||
return new BlockingLoadBalancedRetryPolicy(loadBalancerProperties);
|
||||
return new BlockingLoadBalancedRetryPolicy(loadBalancerFactory.getProperties(serviceId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,10 +23,13 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.blocking.retry.BlockingLoadBalancedRetryFactory;
|
||||
@@ -70,13 +73,14 @@ public class BlockingLoadBalancerClientAutoConfiguration {
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(RetryTemplate.class)
|
||||
@EnableConfigurationProperties(LoadBalancerProperties.class)
|
||||
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
|
||||
protected static class BlockingLoadBalancerRetryConfig {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory(LoadBalancerProperties properties) {
|
||||
return new BlockingLoadBalancedRetryFactory(properties);
|
||||
LoadBalancedRetryFactory loadBalancedRetryFactory(
|
||||
ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {
|
||||
return new BlockingLoadBalancedRetryFactory(loadBalancerFactory);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerBeanPostProcessorAutoConfiguration;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactorLoadBalancerClientAutoConfiguration;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
|
||||
@@ -40,7 +40,7 @@ import org.springframework.core.env.Environment;
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@LoadBalancerClients
|
||||
@EnableConfigurationProperties(LoadBalancerProperties.class)
|
||||
@EnableConfigurationProperties(LoadBalancerClientsProperties.class)
|
||||
@AutoConfigureBefore({ ReactorLoadBalancerClientAutoConfiguration.class,
|
||||
LoadBalancerBeanPostProcessorAutoConfiguration.class })
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.enabled", havingValue = "true", matchIfMissing = true)
|
||||
@@ -60,8 +60,8 @@ public class LoadBalancerAutoConfiguration {
|
||||
|
||||
@ConditionalOnMissingBean
|
||||
@Bean
|
||||
public LoadBalancerClientFactory loadBalancerClientFactory() {
|
||||
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory();
|
||||
public LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) {
|
||||
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory(properties);
|
||||
clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
|
||||
return clientFactory;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.loadbalancer.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.ReactiveLoadBalancer;
|
||||
import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientConfiguration;
|
||||
@@ -36,6 +41,8 @@ import org.springframework.core.env.Environment;
|
||||
public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>
|
||||
implements ReactiveLoadBalancer.Factory<ServiceInstance> {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LoadBalancerClientFactory.class);
|
||||
|
||||
/**
|
||||
* Property source name for load balancer.
|
||||
*/
|
||||
@@ -46,8 +53,16 @@ public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerC
|
||||
*/
|
||||
public static final String PROPERTY_NAME = NAMESPACE + ".client.name";
|
||||
|
||||
private final LoadBalancerClientsProperties properties;
|
||||
|
||||
@Deprecated
|
||||
public LoadBalancerClientFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
|
||||
super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public String getName(Environment environment) {
|
||||
@@ -59,4 +74,21 @@ public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerC
|
||||
return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadBalancerProperties getProperties(String serviceId) {
|
||||
if (properties == null) {
|
||||
if (log.isWarnEnabled()) {
|
||||
log.warn("LoadBalancerClientsProperties is null. Please use the new constructor.");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (!properties.getClients().containsKey(serviceId)) {
|
||||
// no specific client properties, return default
|
||||
return properties;
|
||||
}
|
||||
// because specifics are overlayed on top of defaults, everything in `properties`,
|
||||
// unless overridden, is in `clientsProperties`
|
||||
return properties.getClients().get(serviceId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.client.DefaultServiceInstance;
|
||||
import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerClientsProperties;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
|
||||
@@ -100,8 +101,8 @@ class CachingServiceInstanceListSupplierTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
LoadBalancerClientFactory loadBalancerClientFactory() {
|
||||
return new LoadBalancerClientFactory();
|
||||
LoadBalancerClientFactory loadBalancerClientFactory(LoadBalancerClientsProperties properties) {
|
||||
return new LoadBalancerClientFactory(properties);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -111,8 +112,8 @@ class CachingServiceInstanceListSupplierTests {
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoadBalancerProperties loadBalancerProperties() {
|
||||
return new LoadBalancerProperties();
|
||||
public LoadBalancerClientsProperties loadBalancerClientsProperties() {
|
||||
return new LoadBalancerClientsProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
Reference in New Issue
Block a user