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:
Olga Maciaszek-Sharma
2019-09-09 17:49:46 +02:00
committed by GitHub
parent 8368c10865
commit 19bab039a9
10 changed files with 209 additions and 17 deletions

View File

@@ -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.");
}
}

View File

@@ -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 {
}

View File

@@ -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

View File

@@ -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;
}
}