Renames ServiceInstanceListSuppliers to ServiceInstanceListSupplierBuilder (#761)
Puts static builder() method on ServiceInstanceListSupplier. Deprecates ServiceInstanceListSupplier.fixed(Environment) and replaces with fixed(serviceId).
This commit is contained in:
committed by
spencergibb
parent
2b30b355b6
commit
83bb54bafd
@@ -932,7 +932,7 @@ public class CustomLoadBalancerConfiguration {
|
|||||||
@Bean
|
@Bean
|
||||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder()
|
return ServiceInstanceListSupplier.builder()
|
||||||
.withDiscoveryClient()
|
.withDiscoveryClient()
|
||||||
.withHealthChecks()
|
.withHealthChecks()
|
||||||
.withCaching()
|
.withCaching()
|
||||||
@@ -941,7 +941,7 @@ public class CustomLoadBalancerConfiguration {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
TIP:: In order to make working on your own LoadBalancer configuration easier, we have added some utility methods in `ServiceInstanceListSuppliers` class.
|
TIP:: In order to make working on your own LoadBalancer configuration easier, we have added a `builder()` method to the `ServiceInstanceListSupplier` class.
|
||||||
|
|
||||||
TIP:: You can also use our alternative predefined configurations in place of the default ones by setting the value of `spring.cloud.loadbalancer.configurations` property to `zone-preference` to use `ZonePreferenceServiceInstanceListSupplier` with caching or to `health-check` to use `HealthCheckServiceInstanceListSupplier` with caching.
|
TIP:: You can also use our alternative predefined configurations in place of the default ones by setting the value of `spring.cloud.loadbalancer.configurations` property to `zone-preference` to use `ZonePreferenceServiceInstanceListSupplier` with caching or to `health-check` to use `HealthCheckServiceInstanceListSupplier` with caching.
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
|
|||||||
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
|
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
|
||||||
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
|
import org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer;
|
||||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
|
||||||
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSuppliers;
|
|
||||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
@@ -69,7 +68,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "default", matchIfMissing = true)
|
havingValue = "default", matchIfMissing = true)
|
||||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withDiscoveryClient()
|
||||||
.withCaching().build(context);
|
.withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +79,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "zone-preference")
|
havingValue = "zone-preference")
|
||||||
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withDiscoveryClient()
|
||||||
.withZonePreference().withCaching().build(context);
|
.withZonePreference().withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,7 +90,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "health-check")
|
havingValue = "health-check")
|
||||||
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withDiscoveryClient()
|
||||||
.withHealthChecks().withCaching().build(context);
|
.withHealthChecks().withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,7 +108,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "default", matchIfMissing = true)
|
havingValue = "default", matchIfMissing = true)
|
||||||
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withBlockingDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
|
||||||
.withCaching().build(context);
|
.withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,7 +119,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "zone-preference")
|
havingValue = "zone-preference")
|
||||||
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withBlockingDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
|
||||||
.withZonePreference().withCaching().build(context);
|
.withZonePreference().withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +130,7 @@ public class LoadBalancerClientConfiguration {
|
|||||||
havingValue = "health-check")
|
havingValue = "health-check")
|
||||||
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
|
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
|
||||||
ConfigurableApplicationContext context) {
|
ConfigurableApplicationContext context) {
|
||||||
return ServiceInstanceListSuppliers.builder().withBlockingDiscoveryClient()
|
return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient()
|
||||||
.withHealthChecks().withCaching().build(context);
|
.withHealthChecks().withCaching().build(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,23 +39,32 @@ public interface ServiceInstanceListSupplier
|
|||||||
|
|
||||||
String getServiceId();
|
String getServiceId();
|
||||||
|
|
||||||
|
static ServiceInstanceListSupplierBuilder builder() {
|
||||||
|
return new ServiceInstanceListSupplierBuilder();
|
||||||
|
}
|
||||||
|
|
||||||
static FixedServiceInstanceListSupplier.Builder fixed(Environment environment) {
|
static FixedServiceInstanceListSupplier.Builder fixed(Environment environment) {
|
||||||
return new FixedServiceInstanceListSupplier.Builder(environment);
|
return new FixedServiceInstanceListSupplier.Builder(environment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FixedServiceInstanceListSupplier.SimpleBuilder fixed(String serviceId) {
|
||||||
|
return new FixedServiceInstanceListSupplier.SimpleBuilder(serviceId);
|
||||||
|
}
|
||||||
|
|
||||||
class FixedServiceInstanceListSupplier implements ServiceInstanceListSupplier {
|
class FixedServiceInstanceListSupplier implements ServiceInstanceListSupplier {
|
||||||
|
|
||||||
private final String serviceId;
|
private final String serviceId;
|
||||||
|
|
||||||
private List<ServiceInstance> instances;
|
private List<ServiceInstance> instances;
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static Builder with(Environment env) {
|
public static Builder with(Environment env) {
|
||||||
return new Builder(env);
|
return new Builder(env);
|
||||||
}
|
}
|
||||||
|
|
||||||
private FixedServiceInstanceListSupplier(Environment env,
|
private FixedServiceInstanceListSupplier(String serviceId,
|
||||||
List<ServiceInstance> instances) {
|
List<ServiceInstance> instances) {
|
||||||
this.serviceId = env.getProperty(PROPERTY_NAME);
|
this.serviceId = serviceId;
|
||||||
this.instances = instances;
|
this.instances = instances;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,6 +78,43 @@ public interface ServiceInstanceListSupplier
|
|||||||
return Flux.just(instances);
|
return Flux.just(instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
|
public static final class SimpleBuilder {
|
||||||
|
|
||||||
|
private final ArrayList<ServiceInstance> instances = new ArrayList<>();
|
||||||
|
|
||||||
|
private final String serviceId;
|
||||||
|
|
||||||
|
private SimpleBuilder(String serviceId) {
|
||||||
|
this.serviceId = serviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBuilder instance(ServiceInstance instance) {
|
||||||
|
instances.add(instance);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBuilder instance(int port) {
|
||||||
|
return instance("localhost", port);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleBuilder instance(String host, int port) {
|
||||||
|
DefaultServiceInstance instance = new DefaultServiceInstance(
|
||||||
|
instanceId(serviceId, host, port), serviceId, host, port, false);
|
||||||
|
return instance(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String instanceId(String serviceId, String host, int port) {
|
||||||
|
return serviceId + ":" + host + ":" + port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FixedServiceInstanceListSupplier build() {
|
||||||
|
return new FixedServiceInstanceListSupplier(serviceId, instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
private final Environment env;
|
private final Environment env;
|
||||||
@@ -99,7 +145,8 @@ public interface ServiceInstanceListSupplier
|
|||||||
}
|
}
|
||||||
|
|
||||||
public FixedServiceInstanceListSupplier build() {
|
public FixedServiceInstanceListSupplier build() {
|
||||||
return new FixedServiceInstanceListSupplier(env, instances);
|
return new FixedServiceInstanceListSupplier(
|
||||||
|
env.getProperty(PROPERTY_NAME), instances);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* 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 Builder for creating a {@link ServiceInstanceListSupplier} hierarchy to be used in
|
||||||
|
* {@link ReactorLoadBalancer} configuration.
|
||||||
|
*
|
||||||
|
* @author Spencer Gibb
|
||||||
|
* @author Olga Maciaszek-Sharma
|
||||||
|
*/
|
||||||
|
public final class ServiceInstanceListSupplierBuilder {
|
||||||
|
|
||||||
|
private static final Log LOG = LogFactory
|
||||||
|
.getLog(ServiceInstanceListSupplierBuilder.class);
|
||||||
|
|
||||||
|
private Creator baseCreator;
|
||||||
|
|
||||||
|
private DelegateCreator cachingCreator;
|
||||||
|
|
||||||
|
private final List<DelegateCreator> creators = new ArrayList<>();
|
||||||
|
|
||||||
|
ServiceInstanceListSupplierBuilder() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a blocking {@link DiscoveryClient}-based
|
||||||
|
* {@link DiscoveryClientServiceInstanceListSupplier} as a base
|
||||||
|
* {@link ServiceInstanceListSupplier} in the hierarchy.
|
||||||
|
* @return the {@link ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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 ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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 ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder withBase(
|
||||||
|
ServiceInstanceListSupplier supplier) {
|
||||||
|
this.baseCreator = context -> supplier;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a {@link HealthCheckServiceInstanceListSupplier} to the
|
||||||
|
* {@link ServiceInstanceListSupplier} hierarchy.
|
||||||
|
* @return the {@link ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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 ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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 ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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 ServiceInstanceListSupplierBuilder} object
|
||||||
|
*/
|
||||||
|
public ServiceInstanceListSupplierBuilder 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,246 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -41,7 +41,6 @@ import org.springframework.cloud.client.DefaultServiceInstance;
|
|||||||
import org.springframework.cloud.client.ServiceInstance;
|
import org.springframework.cloud.client.ServiceInstance;
|
||||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
@@ -92,9 +91,8 @@ class HealthCheckServiceInstanceListSupplierTests {
|
|||||||
void shouldCheckInstanceWithProvidedHealthCheckPath() {
|
void shouldCheckInstanceWithProvidedHealthCheckPath() {
|
||||||
healthCheck.getPath().put("ignored-service", "/health");
|
healthCheck.getPath().put("ignored-service", "/health");
|
||||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||||
ServiceInstanceListSupplier.FixedServiceInstanceListSupplier
|
ServiceInstanceListSupplier.fixed("ignored-service").build(), healthCheck,
|
||||||
.with(new MockEnvironment()).build(),
|
webClient);
|
||||||
healthCheck, webClient);
|
|
||||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
||||||
"ignored-service", "127.0.0.1", port, false);
|
"ignored-service", "127.0.0.1", port, false);
|
||||||
|
|
||||||
@@ -107,9 +105,8 @@ class HealthCheckServiceInstanceListSupplierTests {
|
|||||||
@Test
|
@Test
|
||||||
void shouldCheckInstanceWithDefaultHealthCheckPath() {
|
void shouldCheckInstanceWithDefaultHealthCheckPath() {
|
||||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||||
ServiceInstanceListSupplier.FixedServiceInstanceListSupplier
|
ServiceInstanceListSupplier.fixed("ignored-service").build(), healthCheck,
|
||||||
.with(new MockEnvironment()).build(),
|
webClient);
|
||||||
healthCheck, webClient);
|
|
||||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
||||||
"ignored-service", "127.0.0.1", port, false);
|
"ignored-service", "127.0.0.1", port, false);
|
||||||
|
|
||||||
@@ -123,9 +120,8 @@ class HealthCheckServiceInstanceListSupplierTests {
|
|||||||
void shouldReturnFalseIfEndpointNotFound() {
|
void shouldReturnFalseIfEndpointNotFound() {
|
||||||
healthCheck.getPath().put("ignored-service", "/test");
|
healthCheck.getPath().put("ignored-service", "/test");
|
||||||
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
listSupplier = new HealthCheckServiceInstanceListSupplier(
|
||||||
ServiceInstanceListSupplier.FixedServiceInstanceListSupplier
|
ServiceInstanceListSupplier.fixed("ignored-service").build(), healthCheck,
|
||||||
.with(new MockEnvironment()).build(),
|
webClient);
|
||||||
healthCheck, webClient);
|
|
||||||
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
ServiceInstance serviceInstance = new DefaultServiceInstance("ignored-service-1",
|
||||||
"ignored-service", "127.0.0.1", port, false);
|
"ignored-service", "127.0.0.1", port, false);
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class ServiceInstanceListSuppliersTests {
|
public class ServiceInstanceListSupplierBuilderTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBuilder() {
|
public void testBuilder() {
|
||||||
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
||||||
.run(context -> {
|
.run(context -> {
|
||||||
ServiceInstanceListSupplier supplier = ServiceInstanceListSuppliers
|
ServiceInstanceListSupplier supplier = ServiceInstanceListSupplier
|
||||||
.builder().withDiscoveryClient().withHealthChecks()
|
.builder().withDiscoveryClient().withHealthChecks()
|
||||||
.withCaching().build(context);
|
.withCaching().build(context);
|
||||||
assertThat(supplier)
|
assertThat(supplier)
|
||||||
@@ -56,7 +56,7 @@ public class ServiceInstanceListSuppliersTests {
|
|||||||
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
new ApplicationContextRunner().withUserConfiguration(CacheTestConfig.class)
|
||||||
.run(context -> {
|
.run(context -> {
|
||||||
try {
|
try {
|
||||||
ServiceInstanceListSuppliers.builder().withHealthChecks()
|
ServiceInstanceListSupplier.builder().withHealthChecks()
|
||||||
.build(context);
|
.build(context);
|
||||||
fail("Should have thrown exception.");
|
fail("Should have thrown exception.");
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ public class ServiceInstanceListSuppliersTests {
|
|||||||
public void testDelegateReturnedIfLoadBalancerCacheManagerNotAvailable() {
|
public void testDelegateReturnedIfLoadBalancerCacheManagerNotAvailable() {
|
||||||
new ApplicationContextRunner().withUserConfiguration(BaseTestConfig.class)
|
new ApplicationContextRunner().withUserConfiguration(BaseTestConfig.class)
|
||||||
.run(context -> {
|
.run(context -> {
|
||||||
ServiceInstanceListSupplier supplier = ServiceInstanceListSuppliers
|
ServiceInstanceListSupplier supplier = ServiceInstanceListSupplier
|
||||||
.builder().withDiscoveryClient().withHealthChecks()
|
.builder().withDiscoveryClient().withHealthChecks()
|
||||||
.withCaching().build(context);
|
.withCaching().build(context);
|
||||||
assertThat(supplier)
|
assertThat(supplier)
|
||||||
Reference in New Issue
Block a user