Lb configuration builders (#751)
* Adds ServiceInstanceListSuppliers.java with Builder * Implement TODOs. * Add javadocs. * Remove unused type. * Add test. * Safer caching config: resolve LoadBalancerCacheManager lazily. Return delegate if LoadBalancerCacheManager not available. * Switch to using builder in LoadBalancerClientConfiguration. * Autoformatting with spring-java-format. * Update docs. Co-authored-by: Spencer Gibb <spencer@gibb.us>
This commit is contained in:
committed by
GitHub
parent
5f413a7297
commit
8dff101d6f
@@ -917,22 +917,14 @@ public class CustomLoadBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||
ReactiveDiscoveryClient discoveryClient, Environment environment,
|
||||
LoadBalancerZoneConfig zoneConfig,
|
||||
ApplicationContext context) {
|
||||
DiscoveryClientServiceInstanceListSupplier firstDelegate = new DiscoveryClientServiceInstanceListSupplier(
|
||||
discoveryClient, environment);
|
||||
ZonePreferenceServiceInstanceListSupplier delegate = new ZonePreferenceServiceInstanceListSupplier(firstDelegate,
|
||||
zoneConfig);
|
||||
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
|
||||
.getBeanProvider(LoadBalancerCacheManager.class);
|
||||
if (cacheManagerProvider.getIfAvailable() != null) {
|
||||
return new CachingServiceInstanceListSupplier(delegate,
|
||||
cacheManagerProvider.getIfAvailable());
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
ConfigurableApplicationContext context) {
|
||||
return ServiceInstanceListSuppliers.builder()
|
||||
.withDiscoveryClient()
|
||||
.withZonePreference()
|
||||
.withCaching()
|
||||
.build(context);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
=== Instance Health-Check for LoadBalancer
|
||||
@@ -966,25 +958,18 @@ public class CustomLoadBalancerConfiguration {
|
||||
|
||||
@Bean
|
||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||
ReactiveDiscoveryClient discoveryClient, Environment environment,
|
||||
LoadBalancerProperties loadBalancerProperties,
|
||||
ApplicationContext context,
|
||||
InstanceHealthChecker healthChecker) {
|
||||
DiscoveryClientServiceInstanceListSupplier firstDelegate = new DiscoveryClientServiceInstanceListSupplier(
|
||||
discoveryClient, environment);
|
||||
HealthCheckServiceInstanceListSupplier delegate = new HealthCheckServiceInstanceListSupplier(firstDelegate,
|
||||
loadBalancerProperties, healthChecker);
|
||||
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
|
||||
.getBeanProvider(LoadBalancerCacheManager.class);
|
||||
if (cacheManagerProvider.getIfAvailable() != null) {
|
||||
return new CachingServiceInstanceListSupplier(delegate,
|
||||
cacheManagerProvider.getIfAvailable());
|
||||
}
|
||||
return delegate;
|
||||
}
|
||||
ConfigurableApplicationContext context) {
|
||||
return ServiceInstanceListSuppliers.builder()
|
||||
.withDiscoveryClient()
|
||||
.withHealthChecks()
|
||||
.withCaching()
|
||||
.build(context);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
TIP:: In order to make working on your own LoadBalancer configuration easier, we have added some utility methods in `ServiceInstanceListSuppliers` class.
|
||||
|
||||
[[spring-cloud-loadbalancer-starter]]
|
||||
=== Spring Cloud LoadBalancer Starter
|
||||
|
||||
|
||||
@@ -26,16 +26,16 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
|
||||
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.DiscoveryClientServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.DiscoveryClientServiceInstanceSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
|
||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSuppliers;
|
||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceSupplier;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -71,17 +71,9 @@ public class LoadBalancerClientConfiguration {
|
||||
@ConditionalOnBean(ReactiveDiscoveryClient.class)
|
||||
@ConditionalOnMissingBean
|
||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||
ReactiveDiscoveryClient discoveryClient, Environment env,
|
||||
ApplicationContext context) {
|
||||
DiscoveryClientServiceInstanceListSupplier delegate = new DiscoveryClientServiceInstanceListSupplier(
|
||||
discoveryClient, env);
|
||||
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
|
||||
.getBeanProvider(LoadBalancerCacheManager.class);
|
||||
if (cacheManagerProvider.getIfAvailable() != null) {
|
||||
return new CachingServiceInstanceListSupplier(delegate,
|
||||
cacheManagerProvider.getIfAvailable());
|
||||
}
|
||||
return delegate;
|
||||
ConfigurableApplicationContext context) {
|
||||
return ServiceInstanceListSuppliers.builder().withDiscoveryClient()
|
||||
.withCaching().build(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -112,17 +104,9 @@ public class LoadBalancerClientConfiguration {
|
||||
@ConditionalOnBean(DiscoveryClient.class)
|
||||
@ConditionalOnMissingBean
|
||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||
DiscoveryClient discoveryClient, Environment env,
|
||||
ApplicationContext context) {
|
||||
DiscoveryClientServiceInstanceListSupplier delegate = new DiscoveryClientServiceInstanceListSupplier(
|
||||
discoveryClient, env);
|
||||
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
|
||||
.getBeanProvider(LoadBalancerCacheManager.class);
|
||||
if (cacheManagerProvider.getIfAvailable() != null) {
|
||||
return new CachingServiceInstanceListSupplier(delegate,
|
||||
cacheManagerProvider.getIfAvailable());
|
||||
}
|
||||
return delegate;
|
||||
ConfigurableApplicationContext context) {
|
||||
return ServiceInstanceListSuppliers.builder().withBlockingDiscoveryClient()
|
||||
.withCaching().build(context);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -37,7 +37,8 @@ import org.springframework.cloud.client.ServiceInstance;
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class CachingServiceInstanceListSupplier implements ServiceInstanceListSupplier {
|
||||
public class CachingServiceInstanceListSupplier
|
||||
extends DelegatingServiceInstanceListSupplier {
|
||||
|
||||
private static final Log log = LogFactory
|
||||
.getLog(CachingServiceInstanceListSupplier.class);
|
||||
@@ -48,14 +49,12 @@ public class CachingServiceInstanceListSupplier implements ServiceInstanceListSu
|
||||
public static final String SERVICE_INSTANCE_CACHE_NAME = CachingServiceInstanceListSupplier.class
|
||||
.getSimpleName() + "Cache";
|
||||
|
||||
private final ServiceInstanceListSupplier delegate;
|
||||
|
||||
private final Flux<List<ServiceInstance>> serviceInstances;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public CachingServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
|
||||
CacheManager cacheManager) {
|
||||
this.delegate = delegate;
|
||||
super(delegate);
|
||||
this.serviceInstances = CacheFlux.lookup(key -> {
|
||||
// TODO: configurable cache name
|
||||
Cache cache = cacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
|
||||
@@ -70,7 +69,7 @@ public class CachingServiceInstanceListSupplier implements ServiceInstanceListSu
|
||||
return Mono.empty();
|
||||
}
|
||||
return Flux.just(list).materialize().collectList();
|
||||
}, delegate.getServiceId()).onCacheMissResume(this.delegate)
|
||||
}, delegate.getServiceId()).onCacheMissResume(delegate)
|
||||
.andWriteWith((key, signals) -> Flux.fromIterable(signals).dematerialize()
|
||||
.doOnNext(instances -> {
|
||||
Cache cache = cacheManager
|
||||
@@ -87,11 +86,6 @@ public class CachingServiceInstanceListSupplier implements ServiceInstanceListSu
|
||||
}).then());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return delegate.getServiceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<List<ServiceInstance>> get() {
|
||||
return serviceInstances;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.core;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Represents a {@link ServiceInstanceListSupplier} that uses a delegate
|
||||
* {@link ServiceInstanceListSupplier} instance underneath.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public abstract class DelegatingServiceInstanceListSupplier
|
||||
implements ServiceInstanceListSupplier {
|
||||
|
||||
private final ServiceInstanceListSupplier delegate;
|
||||
|
||||
public DelegatingServiceInstanceListSupplier(ServiceInstanceListSupplier delegate) {
|
||||
Assert.notNull(delegate, "delegate may not be null");
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public ServiceInstanceListSupplier getDelegate() {
|
||||
return this.delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return this.delegate.getServiceId();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -45,13 +45,12 @@ import org.springframework.web.util.UriComponentsBuilder;
|
||||
* @since 2.2.0
|
||||
*/
|
||||
public class HealthCheckServiceInstanceListSupplier
|
||||
implements ServiceInstanceListSupplier, InitializingBean, DisposableBean {
|
||||
extends DelegatingServiceInstanceListSupplier
|
||||
implements InitializingBean, DisposableBean {
|
||||
|
||||
private static final Log LOG = LogFactory
|
||||
.getLog(HealthCheckServiceInstanceListSupplier.class);
|
||||
|
||||
private final ServiceInstanceListSupplier delegate;
|
||||
|
||||
private final LoadBalancerProperties.HealthCheck healthCheck;
|
||||
|
||||
private final WebClient webClient;
|
||||
@@ -64,7 +63,7 @@ public class HealthCheckServiceInstanceListSupplier
|
||||
|
||||
public HealthCheckServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
|
||||
LoadBalancerProperties.HealthCheck healthCheck, WebClient webClient) {
|
||||
this.delegate = delegate;
|
||||
super(delegate);
|
||||
this.healthCheck = healthCheck;
|
||||
defaultHealthCheckPath = healthCheck.getPath().getOrDefault("default",
|
||||
"/actuator/health");
|
||||
@@ -121,11 +120,6 @@ public class HealthCheckServiceInstanceListSupplier
|
||||
}).repeatWhen(restart -> restart.delayElements(healthCheck.getInterval()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return delegate.getServiceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<List<ServiceInstance>> get() {
|
||||
return aliveInstancesReplay;
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright 2013-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.loadbalancer.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.cloud.client.discovery.DiscoveryClient;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
|
||||
import org.springframework.cloud.loadbalancer.config.LoadBalancerZoneConfig;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* A utility class providing a {@link Builder} for creating a
|
||||
* {@link ServiceInstanceListSupplier} hierarchy to be used in {@link ReactorLoadBalancer}
|
||||
* configuration.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public abstract class ServiceInstanceListSuppliers {
|
||||
|
||||
private ServiceInstanceListSuppliers() {
|
||||
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows creating a {@link ServiceInstanceListSupplier} instance based on provided
|
||||
* {@link ConfigurableApplicationContext}.
|
||||
*/
|
||||
public interface Creator extends
|
||||
Function<ConfigurableApplicationContext, ServiceInstanceListSupplier> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows creating a {@link ServiceInstanceListSupplier} instance based on provided
|
||||
* {@link ConfigurableApplicationContext} and another
|
||||
* {@link ServiceInstanceListSupplier} instance that will be used as a delegate.
|
||||
*/
|
||||
public interface DelegateCreator extends
|
||||
BiFunction<ConfigurableApplicationContext, ServiceInstanceListSupplier, ServiceInstanceListSupplier> {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A builder for creating a {@link ServiceInstanceListSupplier} hierarchy to be used
|
||||
* in {@link ReactorLoadBalancer} configuration.
|
||||
*/
|
||||
public static class Builder {
|
||||
|
||||
private static final Log LOG = LogFactory.getLog(Builder.class);
|
||||
|
||||
private Creator baseCreator;
|
||||
|
||||
private DelegateCreator cachingCreator;
|
||||
|
||||
private final List<DelegateCreator> creators = new ArrayList<>();
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a blocking {@link DiscoveryClient}-based
|
||||
* {@link DiscoveryClientServiceInstanceListSupplier} as a base
|
||||
* {@link ServiceInstanceListSupplier} in the hierarchy.
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withBlockingDiscoveryClient() {
|
||||
if (baseCreator != null && LOG.isWarnEnabled()) {
|
||||
LOG.warn(
|
||||
"Overriding a previously set baseCreator with a blocking DiscoveryClient baseCreator.");
|
||||
}
|
||||
this.baseCreator = context -> {
|
||||
DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
|
||||
|
||||
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient,
|
||||
context.getEnvironment());
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a {@link ReactiveDiscoveryClient}-based
|
||||
* {@link DiscoveryClientServiceInstanceListSupplier} as a base
|
||||
* {@link ServiceInstanceListSupplier} in the hierarchy.
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withDiscoveryClient() {
|
||||
if (baseCreator != null && LOG.isWarnEnabled()) {
|
||||
LOG.warn(
|
||||
"Overriding a previously set baseCreator with a ReactiveDiscoveryClient baseCreator.");
|
||||
}
|
||||
this.baseCreator = context -> {
|
||||
ReactiveDiscoveryClient discoveryClient = context
|
||||
.getBean(ReactiveDiscoveryClient.class);
|
||||
|
||||
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient,
|
||||
context.getEnvironment());
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a user-provided {@link ServiceInstanceListSupplier} as a base
|
||||
* {@link ServiceInstanceListSupplier} in the hierarchy.
|
||||
* @param supplier a user-provided {@link ServiceInstanceListSupplier} instance
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withBase(ServiceInstanceListSupplier supplier) {
|
||||
this.baseCreator = context -> supplier;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HealthCheckServiceInstanceListSupplier} to the
|
||||
* {@link ServiceInstanceListSupplier} hierarchy.
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withHealthChecks() {
|
||||
DelegateCreator creator = (context, delegate) -> {
|
||||
LoadBalancerProperties properties = context
|
||||
.getBean(LoadBalancerProperties.class);
|
||||
WebClient.Builder webClient = context.getBean(WebClient.Builder.class);
|
||||
return new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
properties.getHealthCheck(), webClient.build());
|
||||
};
|
||||
this.creators.add(creator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link HealthCheckServiceInstanceListSupplier} that uses user-provided
|
||||
* {@link WebClient} instance to the {@link ServiceInstanceListSupplier}
|
||||
* hierarchy.
|
||||
* @param webClient a user-provided {@link WebClient} instance
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withHealthChecks(WebClient webClient) {
|
||||
DelegateCreator creator = (context, delegate) -> {
|
||||
LoadBalancerProperties properties = context
|
||||
.getBean(LoadBalancerProperties.class);
|
||||
return new HealthCheckServiceInstanceListSupplier(delegate,
|
||||
properties.getHealthCheck(), webClient);
|
||||
};
|
||||
this.creators.add(creator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a {@link ZonePreferenceServiceInstanceListSupplier} to the
|
||||
* {@link ServiceInstanceListSupplier} hierarchy.
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withZonePreference() {
|
||||
DelegateCreator creator = (context, delegate) -> {
|
||||
LoadBalancerZoneConfig zoneConfig = context
|
||||
.getBean(LoadBalancerZoneConfig.class);
|
||||
return new ZonePreferenceServiceInstanceListSupplier(delegate,
|
||||
zoneConfig);
|
||||
};
|
||||
this.creators.add(creator);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@link LoadBalancerCacheManager} is available in the context, wraps created
|
||||
* {@link ServiceInstanceListSupplier} hierarchy with a
|
||||
* {@link CachingServiceInstanceListSupplier} instance to provide a caching
|
||||
* mechanism for service instances. Uses {@link ObjectProvider} to lazily resolve
|
||||
* {@link LoadBalancerCacheManager}.
|
||||
* @return the {@link Builder} object
|
||||
*/
|
||||
public Builder withCaching() {
|
||||
if (cachingCreator != null && LOG.isWarnEnabled()) {
|
||||
LOG.warn(
|
||||
"Overriding a previously set cachingCreator with a CachingServiceInstanceListSupplier-based cachingCreator.");
|
||||
}
|
||||
this.cachingCreator = (context, delegate) -> {
|
||||
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
|
||||
.getBeanProvider(LoadBalancerCacheManager.class);
|
||||
if (cacheManagerProvider.getIfAvailable() != null) {
|
||||
return new CachingServiceInstanceListSupplier(delegate,
|
||||
cacheManagerProvider.getIfAvailable());
|
||||
}
|
||||
if (LOG.isWarnEnabled()) {
|
||||
LOG.warn(
|
||||
"LoadBalancerCacheManager not available, returning delegate without caching.");
|
||||
}
|
||||
return delegate;
|
||||
};
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the {@link ServiceInstanceListSupplier} hierarchy.
|
||||
* @param context application context
|
||||
* @return a {@link ServiceInstanceListSupplier} instance on top of the delegate
|
||||
* hierarchy
|
||||
*/
|
||||
public ServiceInstanceListSupplier build(ConfigurableApplicationContext context) {
|
||||
Assert.notNull(baseCreator, "A baseCreator must not be null");
|
||||
|
||||
ServiceInstanceListSupplier supplier = baseCreator.apply(context);
|
||||
|
||||
for (DelegateCreator creator : creators) {
|
||||
supplier = creator.apply(context, supplier);
|
||||
}
|
||||
|
||||
if (this.cachingCreator != null) {
|
||||
supplier = this.cachingCreator.apply(context, supplier);
|
||||
}
|
||||
return supplier;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,30 +36,23 @@ import org.springframework.cloud.loadbalancer.config.LoadBalancerZoneConfig;
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public class ZonePreferenceServiceInstanceListSupplier
|
||||
implements ServiceInstanceListSupplier {
|
||||
extends DelegatingServiceInstanceListSupplier {
|
||||
|
||||
private final String ZONE = "zone";
|
||||
|
||||
private final ServiceInstanceListSupplier delegate;
|
||||
|
||||
private final LoadBalancerZoneConfig zoneConfig;
|
||||
|
||||
private String zone;
|
||||
|
||||
public ZonePreferenceServiceInstanceListSupplier(ServiceInstanceListSupplier delegate,
|
||||
LoadBalancerZoneConfig zoneConfig) {
|
||||
this.delegate = delegate;
|
||||
super(delegate);
|
||||
this.zoneConfig = zoneConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServiceId() {
|
||||
return delegate.getServiceId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flux<List<ServiceInstance>> get() {
|
||||
return delegate.get().map(this::filteredByZone);
|
||||
return getDelegate().get().map(this::filteredByZone);
|
||||
}
|
||||
|
||||
private List<ServiceInstance> filteredByZone(List<ServiceInstance> serviceInstances) {
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2013-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.loadbalancer.core;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.cache.LoadBalancerCacheManager;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
public class ServiceInstanceListSuppliersTests {
|
||||
|
||||
@Test
|
||||
public void testBuilder() {
|
||||
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
||||
.run(context -> {
|
||||
ServiceInstanceListSupplier supplier = ServiceInstanceListSuppliers
|
||||
.builder().withDiscoveryClient().withHealthChecks()
|
||||
.withCaching().build(context);
|
||||
assertThat(supplier)
|
||||
.isInstanceOf(CachingServiceInstanceListSupplier.class);
|
||||
DelegatingServiceInstanceListSupplier delegating = (DelegatingServiceInstanceListSupplier) supplier;
|
||||
assertThat(delegating.getDelegate())
|
||||
.isInstanceOf(HealthCheckServiceInstanceListSupplier.class);
|
||||
delegating = (DelegatingServiceInstanceListSupplier) delegating
|
||||
.getDelegate();
|
||||
assertThat(delegating.getDelegate()).isInstanceOf(
|
||||
DiscoveryClientServiceInstanceListSupplier.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIllegalArgumentExceptionThrownWhenBaseBuilderNull() {
|
||||
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
||||
.run(context -> {
|
||||
try {
|
||||
ServiceInstanceListSuppliers.builder().withHealthChecks()
|
||||
.build(context);
|
||||
fail("Should have thrown exception.");
|
||||
}
|
||||
catch (Exception exception) {
|
||||
assertThat(exception)
|
||||
.isInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDelegateReturnedIfLoadBalancerCacheManagerNotAvailable() {
|
||||
new ApplicationContextRunner().withUserConfiguration(BaseTestConfig.class)
|
||||
.run(context -> {
|
||||
ServiceInstanceListSupplier supplier = ServiceInstanceListSuppliers
|
||||
.builder().withDiscoveryClient().withHealthChecks()
|
||||
.withCaching().build(context);
|
||||
assertThat(supplier)
|
||||
.isNotInstanceOf(CachingServiceInstanceListSupplier.class);
|
||||
assertThat(supplier)
|
||||
.isInstanceOf(HealthCheckServiceInstanceListSupplier.class);
|
||||
DelegatingServiceInstanceListSupplier delegating = (DelegatingServiceInstanceListSupplier) supplier;
|
||||
assertThat(delegating.getDelegate()).isInstanceOf(
|
||||
DiscoveryClientServiceInstanceListSupplier.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Import(BaseTestConfig.class)
|
||||
private static class CacheTestConfig {
|
||||
|
||||
@Bean
|
||||
public LoadBalancerCacheManager cacheManager() {
|
||||
return mock(LoadBalancerCacheManager.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class BaseTestConfig {
|
||||
|
||||
@Bean
|
||||
public ReactiveDiscoveryClient reactiveDiscoveryClient() {
|
||||
return mock(ReactiveDiscoveryClient.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public LoadBalancerProperties loadBalancerProperties() {
|
||||
return new LoadBalancerProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebClient.Builder webClientBuilder() {
|
||||
return WebClient.builder();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user