diff --git a/docs/src/main/asciidoc/spring-cloud-commons.adoc b/docs/src/main/asciidoc/spring-cloud-commons.adoc
index 2d176f94..568246b9 100644
--- a/docs/src/main/asciidoc/spring-cloud-commons.adoc
+++ b/docs/src/main/asciidoc/spring-cloud-commons.adoc
@@ -371,12 +371,13 @@ See {githubroot}/spring-cloud-netflix/blob/master/spring-cloud-netflix-ribbon/sr
IMPORTANT: In order to use a load-balanced `RestTemplate`, you need to have a load-balancer implementation in your classpath.
The recommended implementation is `BlockingLoadBalancerClient`
-- add `org.springframework.cloud:spring-cloud-loadbalancer` in order to use it.
+- add `org.springframework.cloud:spring-cloud-starter-loadbalancer` in order to use it.
The
`RibbonLoadBalancerClient` also can be used, but it's now under maintenance and we do not recommend adding it to new projects.
-WARNING: If you want to use `BlockingLoadBalancerClient`, make sure you do not have
-`RibbonLoadBalancerClient` in the project classpath, as for backward compatibility reasons, it will be used by default.
+WARNING: If you have both `RibbonLoadBalancerClient` and `BlockingLoadBalancerClient`, in order to
+preserve backward compatibility, `RibbonLoadBalancerClient` will be used by default. In order
+to override it, you can set the property `spring.cloud.loadbalancer.ribbon.enabled` to `false`.
=== Spring WebClient as a Load Balancer Client
@@ -411,17 +412,18 @@ The Ribbon client 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-loadbalancer` dependency to your project.
+`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
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 recommned
+spring-cloud-starter-netflix-ribbon is already in maintenance mode, so we do not recommend
adding it to new projects.
-TIP: The `ReactorLoadBalancer` used underneath supports caching. If `cacheManager` is detected,
-cached version of `ServiceInstanceSupplier` will be used. If not, we will retrieve instances
-from discovery service without caching them. We recommend https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html[enabling caching] in your project
-if you use `ReactiveLoadBalancer`.
+IMPORTANT: In order to make use of the more efficient cached version of `ServiceInstanceSupplier`,
+ `spring-cloud-starter-loadbalancer` will *enable caching* by default.
+https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html[Spring Boot Caching]
+mechanism will be used under the hood. If you don't want caching to be used, you can set
+the value of `spring.cache.type` to `none`.
==== Retrying Failed Requests
@@ -541,7 +543,7 @@ TIP: If you see errors such as `java.lang.IllegalArgumentException: Can not set
==== Spring WebFlux WebClient with Reactive Load Balancer
`WebClient` can be configured to use the `ReactiveLoadBalancer`.
-If you add `org.springframework.cloud:spring-cloud-loadbalancer` to your project,
+If you add `org.springframework.cloud:spring-cloud-starter-loadbalancer` to your project,
`ReactorLoadBalancerExchangeFilterFunction` is auto-configured if `spring-webflux` is on the classpath.
The following example shows how to configure a `WebClient` to use reactive load balancer under the hood:
@@ -568,7 +570,7 @@ The `ReactorLoadBalancerClient` is used to create a full physical address.
==== Spring WebFlux WebClient with non-reactive Load Balancer Client
-If you you don't have `org.springframework.cloud:spring-cloud-loadbalancer` in your project,
+If you you don't have `org.springframework.cloud:spring-cloud-starter-loadbalancer` in your project,
but you do have spring-cloud-starter-netflix-ribbon, you can still use `WebClient` with `LoadBalancerClient`. `LoadBalancerExchangeFilterFunction`
will be auto-configured if `spring-webflux` is on the classpath. Please note, however, that this is
uses a non-reactive client under the hood.
diff --git a/pom.xml b/pom.xml
index c79c132b..3295eabb 100644
--- a/pom.xml
+++ b/pom.xml
@@ -155,6 +155,7 @@
spring-cloud-commons
spring-cloud-loadbalancer
spring-cloud-starter
+ spring-cloud-starter-loadbalancer
docs
diff --git a/spring-cloud-commons-dependencies/pom.xml b/spring-cloud-commons-dependencies/pom.xml
index def8023a..2bb8d6aa 100644
--- a/spring-cloud-commons-dependencies/pom.xml
+++ b/spring-cloud-commons-dependencies/pom.xml
@@ -54,6 +54,11 @@
spring-cloud-starter
${project.version}
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+ ${project.version}
+
diff --git a/spring-cloud-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json
index dd3b1a41..b8499d25 100644
--- a/spring-cloud-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json
+++ b/spring-cloud-commons/src/main/resources/META-INF/additional-spring-configuration-metadata.json
@@ -47,6 +47,12 @@
"name": "management.endpoint.env.post.enabled",
"description": "Enables writable environment endpoint.",
"type": "java.lang.Boolean"
+ },
+ {
+ "defaultValue": true,
+ "name": "spring.cloud.loadbalancer.ribbon.enabled",
+ "description": "Causes `RibbonLoadBalancerClient` to be used by default.",
+ "type": "java.lang.Boolean"
}
]
}
diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfiguration.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfiguration.java
index 1aaee4ad..af4a58b4 100644
--- a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfiguration.java
+++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfiguration.java
@@ -23,17 +23,20 @@ import org.apache.commons.logging.LogFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+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.condition.ConditionalOnMissingClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.loadbalancer.AsyncLoadBalancerAutoConfiguration;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
import org.springframework.web.client.RestTemplate;
/**
@@ -60,13 +63,32 @@ public class BlockingLoadBalancerClientAutoConfiguration {
@Bean
@ConditionalOnBean(LoadBalancerClientFactory.class)
@ConditionalOnClass(RestTemplate.class)
- @ConditionalOnMissingBean
- @ConditionalOnMissingClass("org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient")
- public LoadBalancerClient loadBalancerClient(
+ @Conditional(OnNoRibbonDefaultCondition.class)
+ @Primary
+ public LoadBalancerClient blockingLoadBalancerClient(
LoadBalancerClientFactory loadBalancerClientFactory) {
return new BlockingLoadBalancerClient(loadBalancerClientFactory);
}
+ 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 {
+
+ }
+
+ }
+
}
class RibbonWarnLogger {
@@ -79,7 +101,8 @@ class RibbonWarnLogger {
LOG.warn(
"You already have RibbonLoadBalancerClient on your classpath. It will be used by default. To use "
+ BlockingLoadBalancerClient.class.getSimpleName()
- + " remove spring-cloud-starter-netflix-ribbon from your project.");
+ + " set the value of `spring.cloud.loadbalancer.ribbon.enabled` to `false` or "
+ + "remove spring-cloud-starter-netflix-ribbon from your project.");
}
}
diff --git a/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfiguration.java b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfiguration.java
new file mode 100644
index 00000000..2e5ccc7e
--- /dev/null
+++ b/spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.loadbalancer.config;
+
+import org.springframework.boot.autoconfigure.AutoConfigureBefore;
+import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.CacheAspectSupport;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * An AutoConfiguration that automatically enables caching when when Spring Boot and
+ * Spring Framework Cache support classes are present.
+ *
+ * @author Olga Maciaszek-Sharma
+ * @see CacheManager
+ * @see CacheAutoConfiguration
+ * @see CacheAspectSupport
+ */
+@Configuration
+@ConditionalOnClass({ CacheManager.class, CacheAutoConfiguration.class })
+@ConditionalOnMissingBean(CacheAspectSupport.class)
+@EnableCaching
+@AutoConfigureBefore(CacheAutoConfiguration.class)
+public class LoadBalancerCacheAutoConfiguration {
+
+}
diff --git a/spring-cloud-loadbalancer/src/main/resources/META-INF/spring.factories b/spring-cloud-loadbalancer/src/main/resources/META-INF/spring.factories
index 9fa6cb80..3e9c647b 100644
--- a/spring-cloud-loadbalancer/src/main/resources/META-INF/spring.factories
+++ b/spring-cloud-loadbalancer/src/main/resources/META-INF/spring.factories
@@ -1,4 +1,5 @@
# AutoConfiguration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
-org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration
+org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\
+org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration
\ No newline at end of file
diff --git a/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfigurationTests.java b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfigurationTests.java
new file mode 100644
index 00000000..430f9d3a
--- /dev/null
+++ b/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/LoadBalancerCacheAutoConfigurationTests.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cloud.loadbalancer.config;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.jupiter.api.Test;
+
+import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration;
+import org.springframework.boot.test.util.TestPropertyValues;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.support.NoOpCacheManager;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.util.StringUtils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link LoadBalancerCacheAutoConfiguration}.
+ *
+ * @author Olga Maciaszek-Sharma
+ */
+
+class LoadBalancerCacheAutoConfigurationTests {
+
+ @Test
+ void shouldAutoEnableCaching() {
+ AnnotationConfigApplicationContext context = setup("");
+ assertThat(context.getBeansOfType(CacheManager.class)).isNotEmpty();
+ assertThat(context.getBeansOfType(CacheManager.class).get("cacheManager"))
+ .isNotInstanceOf(NoOpCacheManager.class);
+ }
+
+ @Test
+ void shouldUseNoOpCacheIfCacheTypeNone() {
+ AnnotationConfigApplicationContext context = setup("spring.cache.type=none");
+ assertThat(context.getBeansOfType(CacheManager.class)).isNotEmpty();
+ assertThat(context.getBeansOfType(CacheManager.class).get("cacheManager"))
+ .isInstanceOf(NoOpCacheManager.class);
+ }
+
+ private AnnotationConfigApplicationContext setup(String property) {
+ List config = new ArrayList<>();
+ config.add(LoadBalancerCacheAutoConfiguration.class);
+ config.add(CacheAutoConfiguration.class);
+ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
+ if (StringUtils.hasText(property)) {
+ TestPropertyValues.of(property).applyTo(context);
+ }
+ context.register(config.toArray(new Class[0]));
+ context.refresh();
+ return context;
+ }
+
+}
diff --git a/spring-cloud-starter-loadbalancer/pom.xml b/spring-cloud-starter-loadbalancer/pom.xml
new file mode 100644
index 00000000..b579826c
--- /dev/null
+++ b/spring-cloud-starter-loadbalancer/pom.xml
@@ -0,0 +1,39 @@
+
+
+
+ org.springframework.cloud
+ spring-cloud-commons-parent
+ 2.2.0.BUILD-SNAPSHOT
+ ..
+
+ 4.0.0
+
+ spring-cloud-starter-loadbalancer
+ spring-cloud-starter-loadbalancer
+ Spring Cloud Starter LoadBalancer
+ https://projects.spring.io/spring-cloud
+
+ Pivotal Software, Inc.
+ https://www.spring.io
+
+
+ ${basedir}/../..
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter
+
+
+ org.springframework.cloud
+ spring-cloud-loadbalancer
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
\ No newline at end of file
diff --git a/spring-cloud-starter-loadbalancer/src/main/resources/META-INF/spring.provides b/spring-cloud-starter-loadbalancer/src/main/resources/META-INF/spring.provides
new file mode 100644
index 00000000..4c34e82b
--- /dev/null
+++ b/spring-cloud-starter-loadbalancer/src/main/resources/META-INF/spring.provides
@@ -0,0 +1 @@
+provides: spring-cloud-loadbalancer
\ No newline at end of file