Spring Cloud LoadBalancer属于官方开源客户端负载均衡器,底层也是基于RestTemplate拦截器(ClientHttpRequestInterceptor)扩展实现,实现原理与Ribbon相似,区别在于LoadBalancerClient和上下文构建实现有所区别。
01 自动装配
1.1 客户端配置
LoadBalancer依赖spring-cloud-loadbalancer.jar配置自动装配类LoadBalancerAutoConfiguration与BlockingLoadBalancerClientAutoConfiguration,借助spring.factories文件实现配置发现和解析。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.BlockingLoadBalancerClientAutoConfiguration,\
org.springframework.cloud.loadbalancer.config.LoadBalancerCacheAutoConfiguration
@AutoConfigureBefore({ReactorLoadBalancerClientAutoConfiguration.class, LoadBalancerBeanPostProcessorAutoConfiguration.class, ReactiveLoadBalancerAutoConfiguration.class})
public class LoadBalancerAutoConfiguration {
// 客户端配置, 主要通过@LoadBalancerClients注解配置注入
private final ObjectProvider<List<LoadBalancerClientSpecification>> configurations;
public LoadBalancerAutoConfiguration(ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {
this.configurations = configurations;
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerZoneConfig zoneConfig(Environment environment) {
return new LoadBalancerZoneConfig(environment.getProperty("spring.cloud.loadbalancer.zone"));
}
// 目的是构建LoadBalancer上下文
@Bean
@ConditionalOnMissingBean
public LoadBalancerClientFactory loadBalancerClientFactory() {
LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory();
clientFactory.setConfigurations((List)this.configurations.getIfAvailable(Collections::emptyList));
return clientFactory;
}
}
LoadBalancer通过LoadBalancerClientFactory#getContext方法创建客户端配置IOC容器,全局默认客户端配置实现就是LoadBalancerClientConfiguration。
public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification> implements ReactiveLoadBalancer.Factory<ServiceInstance> {
public static final String NAMESPACE = "loadbalancer";
public static final String PROPERTY_NAME = NAMESPACE + ".client.name";
public LoadBalancerClientFactory() {
super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
}
}
LoadBalancer客户端配置是通过@LoadBalancerClients和@LoadBalancerClient注解提供开发人员配置,具体解析过程详见([1.1.3 客户端配置]),创建LoadBalancerClientFactory使用setConfigurations方法设置客户端配置。
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
implements DisposableBean, ApplicationContextAware {
private final String propertySourceName;
private final String propertyName;
// 客户端容器缓存
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
// 配置类
private Map<String, C> configurations = new ConcurrentHashMap<>();
// 父容器
private ApplicationContext parent;
// 默认全局配置
private Class<?> defaultConfigType;
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
this.defaultConfigType = defaultConfigType;
this.propertySourceName = propertySourceName;
this.propertyName = propertyName;
}
protected AnnotationConfigApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
// 创建上下文: 每个客户端使用一个IOC容器管理
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 指定客户端配置
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
// 注册配置实例
context.register(configuration);
}
}
// 全局默认配置
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration: entry.getValue().getConfiguration()) {
context.register(configuration);
}
}
}
// 全局配置类
context.register(PropertyPlaceholderAutoConfiguration.class, defaultConfigType);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource (
this.propertySourceName,
Collections.<String, Object>singletonMap(this.propertyName, name))
);
// 设置IOC父容器
if (this.parent != null) {
context.setParent(this.parent);
context.setClassLoader(this.parent.getClassLoader());
}
context.setDisplayName(generateDisplayName(name));
// 刷新IOC容器
context.refresh();
return context;
}
protected String generateDisplayName(String name) {
return this.getClass().getSimpleName() + "-" + name;
}
}
1.1.1 默认全局配置类
LoadBalancer全局默认配置类为LoadBalancerClientConfiguration,提供Reactor获取服务实例,以及服务实例负载选择。
LoadBalancer使用开关配置开通不同服务实例提供者,如果ReactiveDiscoveryClient实例存在,默认情况通过ServiceInstanceListSupplier.builder().withDiscoveryClient().withCaching().build(context)创建ServiceInstanceListSupplier。如果DiscoveryClient实例存在,那么默认情况通过ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching().build(context)创建ServiceInstanceListSupplier。
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {
private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;
@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
Environment environment, LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnReactiveDiscoveryEnabled
@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER)
public static class ReactiveSupportConfiguration {
// 默认配置
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "default",
matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient().withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "zone-preference")
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient().withZonePreference().withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "health-check")
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder().withDiscoveryClient()
.withHealthChecks().withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
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)
@ConditionalOnBlockingDiscoveryEnabled
@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER + 1)
public static class BlockingSupportConfiguration {
// 默认配置
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "default",
matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withBlockingDiscoveryClient().withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "zone-preference")
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withBlockingDiscoveryClient().withZonePreference()
.withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DiscoveryClient.class)
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations",
havingValue = "health-check")
public ServiceInstanceListSupplier healthCheckDiscoveryClientServiceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withBlockingDiscoveryClient().withHealthChecks()
.withCaching().build(context);
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(DiscoveryClient.class)
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;
}
}
}
public final class ServiceInstanceListSupplierBuilder {
private Creator baseCreator;
private DelegateCreator cachingCreator;
private final List<DelegateCreator> creators = new ArrayList<>();
public ServiceInstanceListSupplierBuilder withBlockingDiscoveryClient() {
this.baseCreator = context -> {
// 获取DiscoveryClient客户端
DiscoveryClient discoveryClient = context.getBean(DiscoveryClient.class);
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient, context.getEnvironment());
};
return this;
}
public ServiceInstanceListSupplierBuilder withDiscoveryClient() {
this.baseCreator = context -> {
// 全局默认配置获取服务发现客户端
ReactiveDiscoveryClient discoveryClient = context.getBean(ReactiveDiscoveryClient.class);
return new DiscoveryClientServiceInstanceListSupplier(discoveryClient, context.getEnvironment());
};
return this;
}
public ServiceInstanceListSupplierBuilder withCaching() {
this.cachingCreator = (context, delegate) -> {
ObjectProvider<LoadBalancerCacheManager> cacheManagerProvider = context.getBeanProvider(LoadBalancerCacheManager.class);
if (cacheManagerProvider.getIfAvailable() != null) {
return new CachingServiceInstanceListSupplier(delegate, cacheManagerProvider.getIfAvailable());
}
return delegate;
};
return this;
}
public ServiceInstanceListSupplier build(ConfigurableApplicationContext context) {
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;
}
}
1.1.2 服务发现客户端
创建ServiceInstanceListSupplier需要依赖ReactiveDiscoveryClient或者DiscoveryClient实例,其中Nacos提供依赖spring-cloud-starter-alibaba-nacos-discovery配置自动装配。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientConfiguration,\
com.alibaba.cloud.nacos.discovery.reactive.NacosReactiveDiscoveryClientConfiguration
public class NacosReactiveDiscoveryClient implements ReactiveDiscoveryClient {
private NacosServiceDiscovery serviceDiscovery;
public NacosReactiveDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {
this.serviceDiscovery = nacosServiceDiscovery;
}
@Override
public Flux<ServiceInstance> getInstances(String serviceId) {
return Mono.justOrEmpty(serviceId).flatMapMany(loadInstancesFromNacos())
.subscribeOn(Schedulers.boundedElastic());
}
}
1.1.3 客户端配置
LoadBalancer申明@LoadBalancerClients和@LoadBalancerClient提供开发人员配置客户端,使用客户端注册者(LoadBalancerClientConfigurationRegistrar)解析为LoadBalancerClientSpecification,接着直接注入IOC容器。所以,LoadBalancerClientFactory实例就能够找到这些客户端配置。
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
LoadBalancerClient[] value() default {};
Class<?>[] defaultConfiguration() default {};
}
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClient {
@AliasFor("name")
String value() default "";
@AliasFor("value")
String name() default "";
Class<?>[] configuration() default {};
}
public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
private static String getClientName(Map<String, Object> client) {
if (client == null) {
return null;
}
String value = (String) client.get("value");
if (!StringUtils.hasText(value)) {
value = (String) client.get("name");
}
if (StringUtils.hasText(value)) {
return value;
}
throw new IllegalStateException(...);
}
private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(LoadBalancerClientSpecification.class);
builder.addConstructorArgValue(name);
builder.addConstructorArgValue(configuration);
registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());
}
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
if (attrs != null && attrs.containsKey("value")) {
AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
for (AnnotationAttributes client : clients) {
registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
}
}
if (attrs != null && attrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
} else {
name = "default." + metadata.getClassName();
}
registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));
}
Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
String name = getClientName(client);
if (name != null) {
registerClientConfiguration(registry, name, client.get("configuration"));
}
}
}
1.1.4 创建负载均衡器
LoadBalancer客户端工厂LoadBalancerClientFactory提供负载均衡各组件获取,大多场景是第一次使用客户端时进行初始化。
public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>
implements ReactiveLoadBalancer.Factory<ServiceInstance> {
public static final String NAMESPACE = "loadbalancer";
public static final String PROPERTY_NAME = NAMESPACE + ".client.name";
public LoadBalancerClientFactory() {
super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
}
public String getName(Environment environment) {
return environment.getProperty(PROPERTY_NAME);
}
@Override
public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
}
}
1.2 拦截器配置
LoadBalancer依赖spring-cloud-commons-xxx.jar提供自动配置类LoadBalancerAutoConfiguration,配置LoadBalancer公共服务全局默认组件。用于申明RestTemplateCustomizer封装拦截器LoadBalancerInterceptor注入RestTemplate组件。
Spring所有单例初始化后筛选SmartInitializingSingleton实例进行调用,主要调用入口就是IOC容器单实例初始化方法DefaultListableBeanFactory#preInstantiateSingleton
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
// 循环RestTemplateCustomizer初始化RestTemplate
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// 负载均衡拦截器
@Bean
public LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
02 RestTemplate拦截器
LoadBalancer基于RestTemplate组件基础,通过扩展RestTemplate拦截器实现客户端服务发现、负载均衡功能,LoadBalancerInterceptor底层依赖LoadBalancerRequestFactory和LoadBalancerClient实现负载均衡。
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
// 负载均衡
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
// URI
final URI originalUri = request.getURI();
// 服务名称=主机名称=域名
String serviceName = originalUri.getHost();
return loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
2.1 创建请求
装饰器模式允许运行时动态添加新功能,而无需修改对象原始代码。所以,LoadBalancer拦截器也是采用装饰器模式增强请求行为,从而根据服务实例获取URL。
public class LoadBalancerRequestFactory {
private LoadBalancerClient loadBalancer;
private List<LoadBalancerRequestTransformer> transformers;
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer,
List<LoadBalancerRequestTransformer> transformers) {
this.loadBalancer = loadBalancer;
this.transformers = transformers;
}
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
final byte[] body, final ClientHttpRequestExecution execution) {
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, this.loadBalancer);
if (this.transformers != null) {
for (LoadBalancerRequestTransformer transformer : this.transformers) {
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
};
}
}
2.2 发送请求
LoadBalancer负载均衡器客户端BlockingLoadBalancerClient发送请求,分为获取负载均衡器、选择负载均衡服务、执行请求发送三个步骤进行处理,负载均衡组件通过LoadBalancerRequestFactory提供。
public class BlockingLoadBalancerClient implements LoadBalancerClient {
private final LoadBalancerClientFactory loadBalancerClientFactory;
public BlockingLoadBalancerClient(LoadBalancerClientFactory loadBalancerClientFactory) {
this.loadBalancerClientFactory = loadBalancerClientFactory;
}
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
// 选择服务实例
ServiceInstance serviceInstance = choose(serviceId);
if (serviceInstance == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
// 发送请求
return execute(serviceId, serviceInstance, request);
}
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
try {
return request.apply(serviceInstance);
} catch (IOException iOException) {
throw iOException;
} catch (Exception exception) {
ReflectionUtils.rethrowRuntimeException(exception);
}
return null;
}
@Override
public URI reconstructURI(ServiceInstance serviceInstance, URI original) {
return LoadBalancerUriTools.reconstructURI(serviceInstance, original);
}
@Override
public ServiceInstance choose(String serviceId) {
// 获取负载均衡器
ReactiveLoadBalancer<ServiceInstance> loadBalancer = loadBalancerClientFactory.getInstance(serviceId);
if (loadBalancer == null) {
return null;
}
// 获取服务实例
Response<ServiceInstance> loadBalancerResponse = Mono.from(loadBalancer.choose()).block();
if (loadBalancerResponse == null) {
return null;
}
// 获取服务
return loadBalancerResponse.getServer();
}
}
03 负载均衡器
RibboLoadBalancern全局默认配置类LoadBalancerClientConfiguration,提供负载均衡器配置为RoundRobinLoadBalancer,负载均衡器主要提供服务选择核心功能。
public interface ReactorLoadBalancer<T> extends ReactiveLoadBalancer<T> {
@SuppressWarnings("rawtypes")
Mono<Response<T>> choose(Request request);
// 选择服务
default Mono<Response<T>> choose() {
return choose(REQUEST);
}
}
轮询负载均衡器使用ObjectProvider<ServiceInstanceListSupplier>获取服务,采用AtomicInteger与取模选取服务实例。
public class RoundRobinLoadBalancer implements ReactorServiceInstanceLoadBalancer {
private final AtomicInteger position;
@Deprecated
private ObjectProvider<ServiceInstanceSupplier> serviceInstanceSupplier;
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private final String serviceId;
public RoundRobinLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId) {
this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));
}
public RoundRobinLoadBalancer(
ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
String serviceId, int seedPosition) {
this.serviceId = serviceId;
this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
this.position = new AtomicInteger(seedPosition);
}
@Override
@SuppressWarnings("rawtypes")
// 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) {
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);
}
private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {
if (instances.isEmpty()) {
return new EmptyResponse();
}
int pos = Math.abs(this.position.incrementAndGet());
ServiceInstance instance = instances.get(pos % instances.size());
return new DefaultResponse(instance);
}
}