Merge branch 'fitzoh-master'

This commit is contained in:
spencergibb
2020-05-19 17:35:35 -04:00
9 changed files with 8 additions and 388 deletions

View File

@@ -16,7 +16,6 @@
package org.springframework.cloud.loadbalancer.annotation;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
@@ -26,16 +25,11 @@ import org.springframework.cloud.client.ConditionalOnReactiveDiscoveryEnabled;
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.CachingServiceInstanceSupplier;
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;
@@ -101,23 +95,6 @@ public class LoadBalancerClientConfiguration {
.withHealthChecks().withCaching().build(context);
}
@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
public ServiceInstanceSupplier discoveryClientServiceInstanceSupplier(
ReactiveDiscoveryClient discoveryClient, Environment env,
ApplicationContext context) {
DiscoveryClientServiceInstanceSupplier delegate = new DiscoveryClientServiceInstanceSupplier(
discoveryClient, env);
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
.getBeanProvider(LoadBalancerCacheManager.class);
if (cacheManagerProvider.getIfAvailable() != null) {
return new CachingServiceInstanceSupplier(delegate,
cacheManagerProvider.getIfAvailable());
}
return delegate;
}
}
@Configuration(proxyBeanMethods = false)
@@ -158,23 +135,6 @@ public class LoadBalancerClientConfiguration {
.withHealthChecks().withCaching().build(context);
}
@Bean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnMissingBean
public ServiceInstanceSupplier discoveryClientServiceInstanceSupplier(
DiscoveryClient discoveryClient, Environment env,
ApplicationContext context) {
DiscoveryClientServiceInstanceSupplier delegate = new DiscoveryClientServiceInstanceSupplier(
discoveryClient, env);
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context
.getBeanProvider(LoadBalancerCacheManager.class);
if (cacheManagerProvider.getIfAvailable() != null) {
return new CachingServiceInstanceSupplier(delegate,
cacheManagerProvider.getIfAvailable());
}
return delegate;
}
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright 2012-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.List;
import reactor.cache.CacheFlux;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cloud.client.ServiceInstance;
/**
* @deprecated Use {@link CachingServiceInstanceListSupplier} instead.
* @author Spencer Gibb
*/
@Deprecated
public class CachingServiceInstanceSupplier implements ServiceInstanceSupplier {
/**
* Name of the service cache instance.
*/
public static final String SERVICE_INSTANCE_CACHE_NAME = CachingServiceInstanceSupplier.class
.getSimpleName() + "Cache";
private final ServiceInstanceSupplier delegate;
private final Flux<ServiceInstance> serviceInstances;
@SuppressWarnings("unchecked")
public CachingServiceInstanceSupplier(ServiceInstanceSupplier delegate,
CacheManager cacheManager) {
this.delegate = delegate;
this.serviceInstances = CacheFlux.lookup(key -> {
// TODO: configurable cache name
Cache cache = cacheManager.getCache(SERVICE_INSTANCE_CACHE_NAME);
List<ServiceInstance> list = cache.get(key, List.class);
if (list == null || list.isEmpty()) {
return Mono.empty();
}
return Flux.fromIterable(list).materialize().collectList();
}, delegate.getServiceId()).onCacheMissResume(this.delegate::get)
.andWriteWith((key, signals) -> Flux.fromIterable(signals).dematerialize()
.cast(ServiceInstance.class).collectList().doOnNext(instances -> {
Cache cache = cacheManager
.getCache(SERVICE_INSTANCE_CACHE_NAME);
cache.put(key, instances);
}).then());
}
@Override
public Flux<ServiceInstance> get() {
return this.serviceInstances;
}
@Override
public String getServiceId() {
return this.delegate.getServiceId();
}
}

View File

@@ -1,64 +0,0 @@
/*
* Copyright 2012-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 reactor.core.publisher.Flux;
import reactor.core.scheduler.Schedulers;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.ReactiveDiscoveryClient;
import org.springframework.core.env.Environment;
import static org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory.PROPERTY_NAME;
/**
* @deprecated Use {@link DiscoveryClientServiceInstanceListSupplier} instead.
* @author Spencer Gibb
* @author Tim Ysewyn
*/
@Deprecated
public class DiscoveryClientServiceInstanceSupplier implements ServiceInstanceSupplier {
private final String serviceId;
private final Flux<ServiceInstance> serviceInstances;
public DiscoveryClientServiceInstanceSupplier(DiscoveryClient delegate,
Environment environment) {
this.serviceId = environment.getProperty(PROPERTY_NAME);
this.serviceInstances = Flux
.defer(() -> Flux.fromIterable(delegate.getInstances(serviceId)))
.subscribeOn(Schedulers.boundedElastic());
}
public DiscoveryClientServiceInstanceSupplier(ReactiveDiscoveryClient delegate,
Environment environment) {
this.serviceId = environment.getProperty(PROPERTY_NAME);
this.serviceInstances = delegate.getInstances(serviceId);
}
@Override
public Flux<ServiceInstance> get() {
return this.serviceInstances;
}
public String getServiceId() {
return this.serviceId;
}
}

View File

@@ -1,42 +0,0 @@
/*
* Copyright 2012-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 reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance;
/**
* A no-op implementation of {@link ServiceInstanceSupplier}.
*
* @author Olga Maciaszek-Sharma
* @deprecated Use {@link NoopServiceInstanceListSupplier} instead.
*/
@Deprecated
public class NoopServiceInstanceSupplier implements ServiceInstanceSupplier {
@Override
public String getServiceId() {
return "";
}
@Override
public Flux<ServiceInstance> get() {
return Flux.empty();
}
}

View File

@@ -43,25 +43,10 @@ public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalance
private final AtomicInteger position;
@Deprecated
private ObjectProvider<ServiceInstanceSupplier> serviceInstanceSupplier;
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private final String serviceId;
/**
* @param serviceId id of the service for which to choose an instance
* @param serviceInstanceSupplier a provider of {@link ServiceInstanceSupplier} that
* will be used to get available instances
* @deprecated Use {@link #RoundRobinLoadBalancer(ObjectProvider, String)}} instead.
*/
@Deprecated
public RoundRobinLoadBalancer(String serviceId,
ObjectProvider<ServiceInstanceSupplier> serviceInstanceSupplier) {
this(serviceId, serviceInstanceSupplier, new Random().nextInt(1000));
}
/**
* @param serviceInstanceListSupplierProvider a provider of
* {@link ServiceInstanceListSupplier} that will be used to get available instances
@@ -87,39 +72,15 @@ public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalance
this.position = new AtomicInteger(seedPosition);
}
/**
* @param serviceId id of the service for which to choose an instance
* @param serviceInstanceSupplier a provider of {@link ServiceInstanceSupplier} that
* will be used to get available instances
* @param seedPosition Round Robin element position marker
* @deprecated Use {@link #RoundRobinLoadBalancer(ObjectProvider, String, int)}}
* instead.
*/
@Deprecated
public RoundRobinLoadBalancer(String serviceId,
ObjectProvider<ServiceInstanceSupplier> serviceInstanceSupplier,
int seedPosition) {
this.serviceId = serviceId;
this.serviceInstanceSupplier = serviceInstanceSupplier;
this.position = new AtomicInteger(seedPosition);
}
@SuppressWarnings("rawtypes")
@Override
// see original
// https://github.com/Netflix/ocelli/blob/master/ocelli-core/
// src/main/java/netflix/ocelli/loadbalancer/RoundRobinLoadBalancer.java
public Mono<Response<ServiceInstance>> choose(Request request) {
// TODO: move supplier to Request?
// Temporary conditional logic till deprecated members are removed.
if (serviceInstanceListSupplierProvider != null) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
ServiceInstanceSupplier supplier = this.serviceInstanceSupplier
.getIfAvailable(NoopServiceInstanceSupplier::new);
return supplier.get().collectList().map(this::getInstanceResponse);
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get().next().map(this::getInstanceResponse);
}
private Response<ServiceInstance> getInstanceResponse(

View File

@@ -1,34 +0,0 @@
/*
* Copyright 2012-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.function.Supplier;
import reactor.core.publisher.Flux;
import org.springframework.cloud.client.ServiceInstance;
/**
* @author Spencer Gibb
* @deprecated Use {@link ServiceInstanceListSupplier} instead.
*/
@Deprecated
public interface ServiceInstanceSupplier extends Supplier<Flux<ServiceInstance>> {
String getServiceId();
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright 2012-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.support;
import reactor.core.publisher.Flux;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceSupplier;
/**
* Utility class for service instances.
*
* @author Spencer Gibb
* @deprecated Use {@link ServiceInstanceListSuppliers} instead.
*/
@Deprecated
public final class ServiceInstanceSuppliers {
private ServiceInstanceSuppliers() {
throw new IllegalStateException("Can't instantiate a utility class");
}
public static ServiceInstanceSupplier from(String serviceId,
ServiceInstance... instances) {
return new ServiceInstanceSupplier() {
@Override
public Flux<ServiceInstance> get() {
return Flux.just(instances);
}
@Override
public String getServiceId() {
return serviceId;
}
};
}
public static ObjectProvider<ServiceInstanceSupplier> toProvider(String serviceId,
ServiceInstance... instances) {
return new SimpleObjectProvider<>(from(serviceId, instances));
}
}

View File

@@ -26,12 +26,10 @@ import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
import org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceSupplier;
import org.springframework.cloud.loadbalancer.core.DelegatingServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.DiscoveryClientServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.HealthCheckServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceSupplier;
import org.springframework.cloud.loadbalancer.core.ZonePreferenceServiceInstanceListSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -150,18 +148,6 @@ class LoadBalancerClientConfigurationTests {
});
}
@Test
void shouldInstantiateServiceInstanceSupplierRegardlessOfConfigurationProperty() {
reactiveDiscoveryClientRunner
.withPropertyValues(
"spring.cloud.loadbalancer.configurations=zone-preference")
.run(context -> {
ServiceInstanceSupplier supplier = context
.getBean(ServiceInstanceSupplier.class);
then(supplier).isInstanceOf(CachingServiceInstanceSupplier.class);
});
}
@Configuration
protected static class TestConfig {

View File

@@ -44,7 +44,6 @@ import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClient;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.cloud.loadbalancer.support.ServiceInstanceListSuppliers;
import org.springframework.cloud.loadbalancer.support.ServiceInstanceSuppliers;
import org.springframework.context.annotation.Bean;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
@@ -122,22 +121,6 @@ public class LoadBalancerTests {
@Test
public void staticConfigurationWorks() {
String serviceId = "test1";
RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(serviceId,
ServiceInstanceSuppliers.toProvider(serviceId,
instance(serviceId, "1host", false),
instance(serviceId, "2host-secure", true)),
-1);
assertLoadBalancer(loadBalancer, Arrays.asList("1host", "2host-secure"));
}
private static DefaultServiceInstance instance(String serviceId, String host,
boolean secure) {
return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure);
}
@Test
public void staticConfigurationWorksWithServiceInstanceListSupplier() {
String serviceId = "test1";
RoundRobinLoadBalancer loadBalancer = new RoundRobinLoadBalancer(
ServiceInstanceListSuppliers.toProvider(serviceId,
@@ -147,6 +130,11 @@ public class LoadBalancerTests {
assertLoadBalancer(loadBalancer, Arrays.asList("1host", "2host-secure"));
}
private static DefaultServiceInstance instance(String serviceId, String host,
boolean secure) {
return new DefaultServiceInstance(serviceId, serviceId, host, 80, secure);
}
@SuppressWarnings("ConstantConditions")
@Test
public void canPassHintViaRequest() {