Use Ribbon by default. (#609)
* Use Ribbon by default. * Fix after review. * Reformat.
This commit is contained in:
committed by
GitHub
parent
da0ce3c4c8
commit
87fa3c7897
@@ -407,16 +407,19 @@ public class MyClass {
|
||||
----
|
||||
|
||||
The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The Ribbon client is used to create a full physical address.
|
||||
The Ribbon client or Spring Cloud LoadBalancer is used to create a full physical address.
|
||||
|
||||
IMPORTANT: If you want to use a `@LoadBalanced WebClient.Builder`, you need to have a loadbalancer
|
||||
implementation in the classpath. It is recommended that you add the
|
||||
`org.springframework.cloud:spring-cloud-starter-loadbalancer` dependency to your project.
|
||||
Then, `ReactiveLoadBalancer` will be used underneath.
|
||||
Alternatively, this functionality will also work with spring-cloud-starter-netflix-ribbon, but the request
|
||||
Alternatively, this functionality will also work with `spring-cloud-starter-netflix-ribbon`, but the request
|
||||
will be handled by a non-reactive `LoadBalancerClient` under the hood. Additionally,
|
||||
spring-cloud-starter-netflix-ribbon is already in maintenance mode, so we do not recommend
|
||||
adding it to new projects.
|
||||
If you have both `spring-cloud-starter-loadbalancer` and `spring-cloud-starter-netflix-ribbon`
|
||||
in your classpath, Ribbon will be used by default. In order to switch to Spring Cloud LoadBalancer,
|
||||
set the value of `spring.cloud.loadbalancer.ribbon.enabled` to false.
|
||||
|
||||
IMPORTANT: In order to make use of the more efficient cached version of `ServiceInstanceListSupplier`,
|
||||
`spring-cloud-starter-loadbalancer` will *enable caching* by default.
|
||||
@@ -565,8 +568,14 @@ public class MyClass {
|
||||
----
|
||||
|
||||
The URI needs to use a virtual host name (that is, a service name, not a host name).
|
||||
The `ReactorLoadBalancerClient` is used to create a full physical address.
|
||||
The `ReactorLoadBalancer` is used to create a full physical address.
|
||||
|
||||
NOTE: If you have `spring-cloud-netflix-ribbon` in your classpath, <<load-balancer-exchange-filter-function,`LoadBalancerExchangeFilterFunction`>>
|
||||
will be used by default to maintain backward compatibility. In order to be able to use
|
||||
`ReactorLoadBalancerExchangeFilterFunction`, set the value of `spring.cloud.loadbalancer.ribbon.enabled` property
|
||||
to `false`.
|
||||
|
||||
[[load-balancer-exchange-filter-function]]
|
||||
==== Spring WebFlux WebClient with non-reactive Load Balancer Client
|
||||
|
||||
If you you don't have `org.springframework.cloud:spring-cloud-starter-loadbalancer` in your project,
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
@@ -38,7 +39,8 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@Configuration
|
||||
@ConditionalOnClass(WebClient.class)
|
||||
@ConditionalOnBean(LoadBalancerClient.class)
|
||||
@ConditionalOnMissingBean(ReactiveLoadBalancer.Factory.class)
|
||||
@AutoConfigureAfter(ReactorLoadBalancerClientAutoConfiguration.class)
|
||||
@ConditionalOnMissingBean(ReactorLoadBalancerExchangeFilterFunction.class)
|
||||
@Deprecated
|
||||
public class ReactiveLoadBalancerAutoConfiguration {
|
||||
|
||||
|
||||
@@ -19,12 +19,21 @@ package org.springframework.cloud.client.loadbalancer.reactive;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.SmartInitializingSingleton;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
@@ -41,40 +50,92 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
@ConditionalOnBean(ReactiveLoadBalancer.Factory.class)
|
||||
public class ReactorLoadBalancerClientAutoConfiguration {
|
||||
|
||||
private List<WebClient.Builder> webClientBuilders = Collections.emptyList();
|
||||
|
||||
List<WebClient.Builder> getBuilders() {
|
||||
return this.webClientBuilders;
|
||||
@Bean
|
||||
@ConditionalOnClass(
|
||||
name = "org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient")
|
||||
public ReactorLoadBalancerClientRibbonWarnLogger reactorLoadBalancerClientRibbonWarnLogger() {
|
||||
return new ReactorLoadBalancerClientRibbonWarnLogger();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmartInitializingSingleton loadBalancedWebClientInitializer(
|
||||
final List<WebClientCustomizer> customizers) {
|
||||
return () -> {
|
||||
for (WebClient.Builder webClientBuilder : getBuilders()) {
|
||||
for (WebClientCustomizer customizer : customizers) {
|
||||
customizer.customize(webClientBuilder);
|
||||
@Configuration
|
||||
@Conditional(OnNoRibbonDefaultCondition.class)
|
||||
protected static class ReactorLoadBalancerExchangeFilterFunctionConfig {
|
||||
|
||||
private List<WebClient.Builder> webClientBuilders = Collections.emptyList();
|
||||
|
||||
List<WebClient.Builder> getBuilders() {
|
||||
return this.webClientBuilders;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SmartInitializingSingleton loadBalancedWebClientInitializer(
|
||||
final List<WebClientCustomizer> customizers) {
|
||||
return () -> {
|
||||
for (WebClient.Builder webClientBuilder : getBuilders()) {
|
||||
for (WebClientCustomizer customizer : customizers) {
|
||||
customizer.customize(webClientBuilder);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebClientCustomizer loadBalancerClientWebClientCustomizer(
|
||||
ReactorLoadBalancerExchangeFilterFunction filterFunction) {
|
||||
return builder -> builder.filter(filterFunction);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReactorLoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(
|
||||
ReactiveLoadBalancer.Factory loadBalancerFactory) {
|
||||
return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory);
|
||||
}
|
||||
|
||||
@LoadBalanced
|
||||
@Autowired(required = false)
|
||||
void setWebClientBuilders(List<WebClient.Builder> webClientBuilders) {
|
||||
this.webClientBuilders = webClientBuilders;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class OnNoRibbonDefaultCondition extends AnyNestedCondition {
|
||||
|
||||
private OnNoRibbonDefaultCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.ribbon.enabled",
|
||||
havingValue = "false")
|
||||
static class RibbonNotEnabled {
|
||||
|
||||
}
|
||||
|
||||
@ConditionalOnMissingClass("org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient")
|
||||
static class RibbonLoadBalancerNotPresent {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ReactorLoadBalancerClientRibbonWarnLogger {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(ReactorLoadBalancerClientRibbonWarnLogger.class);
|
||||
|
||||
@PostConstruct
|
||||
void logWarning() {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn("You have RibbonLoadBalancerClient on your classpath. "
|
||||
+ "LoadBalancerExchangeFilterFunction that uses it under the "
|
||||
+ "hood will be used by default. Spring Cloud Ribbon is now in maintenance mode, "
|
||||
+ "so we suggest switching to "
|
||||
+ ReactorLoadBalancerExchangeFilterFunction.class.getSimpleName()
|
||||
+ " instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or "
|
||||
+ "remove spring-cloud-starter-netflix-ribbon from your project.");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebClientCustomizer loadBalancerClientWebClientCustomizer(
|
||||
ReactorLoadBalancerExchangeFilterFunction filterFunction) {
|
||||
return builder -> builder.filter(filterFunction);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ReactorLoadBalancerExchangeFilterFunction loadBalancerExchangeFilterFunction(
|
||||
ReactiveLoadBalancer.Factory loadBalancerFactory) {
|
||||
return new ReactorLoadBalancerExchangeFilterFunction(loadBalancerFactory);
|
||||
}
|
||||
|
||||
@LoadBalanced
|
||||
@Autowired(required = false)
|
||||
void setWebClientBuilders(List<WebClient.Builder> webClientBuilders) {
|
||||
this.webClientBuilders = webClientBuilders;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ReactiveLoadBalancerAutoConfigurationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void autoConfigurationNotLoadedWhenReactorLoadBalancerClientPresent() {
|
||||
public void autoConfigurationNotLoadedWhenReactorLoadBalancerExchangeFilterFunctionPresent() {
|
||||
ConfigurableApplicationContext context = init(
|
||||
ReactorLoadBalancerClientPresent.class);
|
||||
final Map<String, WebClient.Builder> webClientBuilders = context
|
||||
@@ -139,6 +139,12 @@ public class ReactiveLoadBalancerAutoConfigurationTests {
|
||||
return serviceId -> new TestReactiveLoadBalancer();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ReactorLoadBalancerExchangeFilterFunction reactorLoadBalancerExchangeFilterFunction() {
|
||||
return new ReactorLoadBalancerExchangeFilterFunction(
|
||||
reactiveLoadBalancerFactory());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
|
||||
@@ -55,8 +55,8 @@ public class BlockingLoadBalancerClientAutoConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnClass(
|
||||
name = "org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient")
|
||||
public RibbonWarnLogger ribbonWarnLogger() {
|
||||
return new RibbonWarnLogger();
|
||||
public BlockingLoadBalancerClientRibbonWarnLogger blockingLoadBalancerClientRibbonWarnLogger() {
|
||||
return new BlockingLoadBalancerClientRibbonWarnLogger();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -93,17 +93,19 @@ public class BlockingLoadBalancerClientAutoConfiguration {
|
||||
|
||||
}
|
||||
|
||||
static class RibbonWarnLogger {
|
||||
static class BlockingLoadBalancerClientRibbonWarnLogger {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(RibbonWarnLogger.class);
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(BlockingLoadBalancerClientRibbonWarnLogger.class);
|
||||
|
||||
@PostConstruct
|
||||
void logWarning() {
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn(
|
||||
"You already have RibbonLoadBalancerClient on your classpath. It will be used by default. To use "
|
||||
"You already have RibbonLoadBalancerClient on your classpath. It will be used by default. "
|
||||
+ "As Spring Cloud Ribbon is in maintenance mode. We recommend switching to "
|
||||
+ BlockingLoadBalancerClient.class.getSimpleName()
|
||||
+ " set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or "
|
||||
+ " instead. In order to use it, set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or "
|
||||
+ "remove spring-cloud-starter-netflix-ribbon from your project.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration.RibbonWarnLogger;
|
||||
import org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration.BlockingLoadBalancerClientRibbonWarnLogger;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -44,7 +44,8 @@ public class BlockingLoadBalancerClientAutoConfigurationTests {
|
||||
public void beansCreatedNormally() {
|
||||
applicationContextRunner.run(ctxt -> {
|
||||
assertThat(ctxt).hasSingleBean(BlockingLoadBalancerClient.class);
|
||||
assertThat(ctxt).doesNotHaveBean(RibbonWarnLogger.class);
|
||||
assertThat(ctxt)
|
||||
.doesNotHaveBean(BlockingLoadBalancerClientRibbonWarnLogger.class);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -54,7 +55,8 @@ public class BlockingLoadBalancerClientAutoConfigurationTests {
|
||||
.withClassLoader(new FilteredClassLoader(RestTemplate.class))
|
||||
.run(context -> {
|
||||
assertThat(context).doesNotHaveBean(BlockingLoadBalancerClient.class);
|
||||
assertThat(context).doesNotHaveBean(RibbonWarnLogger.class);
|
||||
assertThat(context).doesNotHaveBean(
|
||||
BlockingLoadBalancerClientRibbonWarnLogger.class);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user