关于spring-cloud:SpringCloud升级之路20200x版22Spring-Cloud-LoadBalancer核心源码

26次阅读

共计 8502 个字符,预计需要花费 22 分钟才能阅读完成。

本系列代码地址:https://github.com/HashZhang/…

通过上一节的详细分析,咱们晓得能够通过 LoadBalancerClientFactory 晓得 默认配置类 LoadBalancerClientConfiguration. 并且 获取微服务名称 能够通过 environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);

[LoadBalancerClientFactory]()

public static final String NAMESPACE = "loadbalancer";
public static final String PROPERTY_NAME = NAMESPACE + ".client.name";
public LoadBalancerClientFactory() {super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
}

查看配置类 LoadBalancerClientConfiguration,咱们能够发现这个类次要定义两种 Bean,别离是 ReactorLoadBalancer<ServiceInstance>ServiceInstanceListSupplier

ReactorLoadBalancer 是负载均衡器,次要提供依据服务名称获取服务实例列表并从从中抉择的性能。

[ReactorLoadBalancer]()

Mono<Response<T>> choose(Request request);

在默认配置中的实现是:

[LoadBalancerClientConfiguration]()

@Bean
@ConditionalOnMissingBean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(
        Environment environment,
        LoadBalancerClientFactory loadBalancerClientFactory) {
    // 获取微服务名称
    String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
    // 创立 RoundRobinLoadBalancer 
    // 留神这里注入的是 LazyProvider,这次要因为在注册这个 Bean 的时候相干的 Bean 可能还没有被加载注册,利用 LazyProvider 而不是间接注入所需的 Bean 避免报找不到 Bean 注入的谬误。return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name,
            ServiceInstanceListSupplier.class), name);
}

能够看出,默认配置的 ReactorLoadBalancer 实现是 RoundRobinLoadBalancer。这个负载均衡器实现很简略,有一个原子类型的 AtomicInteger position,从 ServiceInstanceListSupplier 中读取所有的服务实例列表,而后对于 position 原子加 1,对列表大小取模,返回列表中这个地位的服务实例 ServiceInstance

[RoundRobinLoadBalancer]()

public Mono<Response<ServiceInstance>> choose(Request request) {
    // 注入的时候注入的是 Lazy Provider,这里取出真正的 Bean,也就是 ServiceInstanceListSupplier
    ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
            .getIfAvailable(NoopServiceInstanceListSupplier::new);
            // 获取实例列表
    return supplier.get(request)
            .next()
            // 从列表中抉择一个实例
            .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances));
}

private Response<ServiceInstance> processInstanceResponse(ServiceInstanceListSupplier supplier,
        List<ServiceInstance> serviceInstances) {Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(serviceInstances);
    // 如果 ServiceInstanceListSupplier 也实现了 SelectedInstanceCallback,则执行上面的逻辑进行回调。SelectedInstanceCallback 就是每次负载均衡器抉择实例之后进行的回调
    if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
    }
    return serviceInstanceResponse;
}

private Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances) {if (instances.isEmpty()) {return new EmptyResponse();
    }
    //postion 原子 +1 并取绝对值
    int pos = Math.abs(this.position.incrementAndGet());
    // 返回对应下标的实例
    ServiceInstance instance = instances.get(pos % instances.size());
    return new DefaultResponse(instance);
}

ServiceInstanceListSupplier 是服务列表提供者接口:

[ServiceInstanceListSupplier]()

public interface ServiceInstanceListSupplier extends Supplier<Flux<List<ServiceInstance>>> {String getServiceId();
    default Flux<List<ServiceInstance>> get(Request request) {return get();
    }
    static ServiceInstanceListSupplierBuilder builder() {return new ServiceInstanceListSupplierBuilder();
    }
}

spring-cloud-loadbalancer 中有很多 ServiceInstanceListSupplier 的实现,在默认配置中是通过属性配置指定实现的,这个配置项是spring.cloud.loadbalancer.configurations。例如:

[LoadBalancerClientConfiguration]()

@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
//spring.cloud.loadbalancer.configurations 未指定或者为 default
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "default",
        matchIfMissing = true)
public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {return ServiceInstanceListSupplier.builder()
    // 通过 DiscoveryClient 提供实例
    .withDiscoveryClient()
    // 开启缓存
    .withCaching()
    .build(context);
}

@Bean
@ConditionalOnBean(ReactiveDiscoveryClient.class)
@ConditionalOnMissingBean
// 如果 spring.cloud.loadbalancer.configurations 指定为 zone-preference
@ConditionalOnProperty(value = "spring.cloud.loadbalancer.configurations", havingValue = "zone-preference")
public ServiceInstanceListSupplier zonePreferenceDiscoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {return ServiceInstanceListSupplier.builder()
    // 通过 DiscoveryClient 提供实例
    .withDiscoveryClient()
    // 启用更偏向于同一个 zone 下实例的个性
    .withZonePreference()
    // 开启缓存
    .withCaching()
            .build(context);
}

能够看到,能够通过 ServiceInstanceListSupplier.builder() 生成官网封装好各种个性的 ServiceInstanceListSupplier。其实从底层实现能够看出,所有的 ServiceInstanceListSupplier 实现都是代理模式,例如对于默认配置,底层代码近似于:

return  // 开启服务实例缓存
        new CachingServiceInstanceListSupplier(
                        // 启用通过 discoveryClient 的服务发现
                        new DiscoveryClientServiceInstanceListSupplier(discoveryClient, env)
                , cacheManagerProvider.getIfAvailable());

除了默认配置 LoadBalancerClientConfiguration,用户配置自定义配置则是通过 @LoadBalancerClients@LoadBalancerClient. 这个原理是通过 LoadBalancerClientConfigurationRegistrar 实现的。首先,咱们来看一下 LoadBalancerClientFactory 这个 NamedContextFactory 是如何创立的:

[LoadBalancerAutoConfiguration]

private final ObjectProvider<List<LoadBalancerClientSpecification>> configurations;

public LoadBalancerAutoConfiguration(ObjectProvider<List<LoadBalancerClientSpecification>> configurations) {
    // 注入 LoadBalancerClientSpecification List 的 provider
    // 在 Bean 创立的时候,进行载入,而不是注册的时候
    this.configurations = configurations;
}

@ConditionalOnMissingBean
@Bean
public LoadBalancerClientFactory loadBalancerClientFactory() {
    // 创立 LoadBalancerClientFactory
    LoadBalancerClientFactory clientFactory = new LoadBalancerClientFactory();
    // 读取所有的 LoadBalancerClientSpecification,设置为 LoadBalancerClientFactory 的配置
    clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList));
    return clientFactory;
}

那么,LoadBalancerClientSpecification 这些 Bean 是怎么创立的呢?在 @LoadBalancerClients@LoadBalancerClient 注解中,都蕴含 @Import(LoadBalancerClientConfigurationRegistrar.class)。这个 @Import 加载一个 ImportBeanDefinitionRegistrar,这里是 LoadBalancerClientConfigurationRegistrar. ImportBeanDefinitionRegistrar外面的办法参数蕴含 注解元数据,以及注册 Bean 的 BeanDefinitionRegistry。个别通过注解元数据,动静通过 BeanDefinitionRegistry 注册 Bean,在这里的实现是:

[LoadBalancerClients]

@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {
    // 能够指定多个 LoadBalancerClient
    LoadBalancerClient[] value() default {};
    // 指定所有的负载平衡配置的默认配置
    Class<?>[] defaultConfiguration() default {};}

[LoadBalancerClient]

@Configuration(proxyBeanMethods = false)
@Import(LoadBalancerClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient {
    //name 和 value 都是微服务名称
    @AliasFor("name")
    String value() default "";
    @AliasFor("value")
    String name() default "";
    // 这个微服务的配置
    Class<?>[] configuration() default {};}

[LoadBalancerClientConfigurationRegistrar]

@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    // 获取 LoadBalancerClients 注解的元数据
    Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
    if (attrs != null && attrs.containsKey("value")) {AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
        // 对于 value 属性,其实就是一个 LoadBalancerClient 列表,对于每个生成一个特定微服务名字的  LoadBalancerClientSpecification
        for (AnnotationAttributes client : clients) {registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
        }
    }
    // 如果指定了 defaultConfiguration,则注册为 default 的配置
    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"));
    }
    // 获取 LoadBalancerClient 注解的元数据
    Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
    String name = getClientName(client);
    if (name != null) {registerClientConfiguration(registry, name, client.get("configuration"));
    }
}

private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name, Object configuration) {
    // 初始化 LoadBalancerClientSpecification 的 BeanDefinition,用于注册一个 LoadBalancerClientSpecification Bean
    BeanDefinitionBuilder builder = BeanDefinitionBuilder
            .genericBeanDefinition(LoadBalancerClientSpecification.class);
    // 结构器参数
    builder.addConstructorArgValue(name);
    builder.addConstructorArgValue(configuration);
    // 注册 Bean
    registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());
}

从代码中咱们能够看出,通过应用 @LoadBalancerClients@LoadBalancerClient 注解能够主动生成对应的 LoadBalancerClientSpecification 进而实现公共负载平衡配置或者特定某个微服务的负载平衡配置。

咱们这一节详细分析 Spring Cloud LoadBalancer 的源代码来了解其中的原理,下一节咱们将介绍在咱们我的项目中应用 Spring Cloud LoadBalancer 要实现的性能。

微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种 offer

正文完
 0