Gh 586 loadbalancer starter (#599)
* Add loadbalancer starter. Add property to set BlockingLoadBalancerClient as default non-reactive loadbalancer. Start working on auto-enabling caching. * Automatically enable caching. Fixes gh-585. * Add tests. * Add reference docs. * Change property name.
This commit is contained in:
committed by
GitHub
parent
8368c10865
commit
19bab039a9
@@ -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.
|
||||
|
||||
1
pom.xml
1
pom.xml
@@ -155,6 +155,7 @@
|
||||
<module>spring-cloud-commons</module>
|
||||
<module>spring-cloud-loadbalancer</module>
|
||||
<module>spring-cloud-starter</module>
|
||||
<module>spring-cloud-starter-loadbalancer</module>
|
||||
<module>docs</module>
|
||||
</modules>
|
||||
</project>
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
<artifactId>spring-cloud-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
<profiles>
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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<Class> 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;
|
||||
}
|
||||
|
||||
}
|
||||
39
spring-cloud-starter-loadbalancer/pom.xml
Normal file
39
spring-cloud-starter-loadbalancer/pom.xml
Normal file
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-parent</artifactId>
|
||||
<version>2.2.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
|
||||
<name>spring-cloud-starter-loadbalancer</name>
|
||||
<description>Spring Cloud Starter LoadBalancer</description>
|
||||
<url>https://projects.spring.io/spring-cloud</url>
|
||||
<organization>
|
||||
<name>Pivotal Software, Inc.</name>
|
||||
<url>https://www.spring.io</url>
|
||||
</organization>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../..</main.basedir>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-loadbalancer</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
provides: spring-cloud-loadbalancer
|
||||
Reference in New Issue
Block a user