Spring-Cloud-Loadblancer详细分析_2

@LoadBalancerClients

终于分析到了此注解的作用,它是实现不同服务之间的配置隔离的关键

@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {LoadBalancerClient[] value() default {};/*** {@link LoadBalancerClientConfigurationRegistrar} creates a* {@link LoadBalancerClientSpecification} with this as an argument. These in turn are* added as default contexts in {@link LoadBalancerClientFactory}. Configuration* defined in these classes are used as defaults if values aren't defined via* {@link LoadBalancerClient#configuration()}* @return classes for default configurations*/Class<?>[] defaultConfiguration() default {};}@Configuration(proxyBeanMethods = false)
@Import(LoadBalancerClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient {/*** Synonym for name (the name of the client).** @see #name()* @return the name of the load balancer client*/@AliasFor("name")String value() default "";/*** The name of the load balancer client, uniquely identifying a set of client* resources, including a load balancer.* @return the name of the load balancer client*/@AliasFor("value")String name() default "";/*** A custom <code>@Configuration</code> for the load balancer client. Can contain* override <code>@Bean</code> definition for the pieces that make up the client.** @see LoadBalancerClientConfiguration for the defaults* @return configuration classes for the load balancer client.*/Class<?>[] configuration() default {};}
  • LoadBalancerClients 就是其实就是多个LoadBalancerClient
  • LoadBalancerClient 相当于一个负载均衡配置,name/value 就是 serviceId,configuration 就是负载均衡配置
  • 通过@Import(LoadBalancerClientConfigurationRegistrar.class)来进行注入

LoadBalancerClientConfigurationRegistrar

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("Either 'name' or 'value' must be provided in @LoadBalancerClient");}private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,Object configuration) {BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(LoadBalancerClientSpecification.class);builder.addConstructorArgValue(name);builder.addConstructorArgValue(configuration);//每个LoadBalancerClient其实就是LoadBalancerClientSpecificationregistry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());}@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);//获取LoadBalancerClients 注解的属性if (attrs != null && attrs.containsKey("value")) {//value属性为LoadBalancerClient注解,可以给configuration赋值,填写需要的配置类,比如RandomLoadBalancerConfig.classAnnotationAttributes[] 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();}//如果defaultConfiguration有配置,当做默认配置注册中,并赋值给所有容器registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));}//处理@LoadBalancerClient注解,逻辑和上面LoadBalancerClients的相同Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);String name = getClientName(client);if (name != null) {//configuration 属性的类 注册到容器中registerClientConfiguration(registry, name, client.get("configuration"));}}}
  • LoadBalancerClients有一个默认的配置属性 Class<?>[] configuration() default {};这个属性的类以default. 开头来命名
  • LoadBalancerClients含有多个LoadBalancerClient,属性valueserviceId属性 Class<?>[] configuration() default {};是当前serviceId名字下的配置
  • LoadBalancerClients和每个LoadBalancerClientconfiguration都会被封装以clientName为维度的LoadBalancerClientSpecification,注册到当前容器中
  • 注意! 这时注册的是BeanDefinition类型的元数据,还没有开始真正的实例化bean!真正的实例化是在子容器创建的时候会将父容器添加进去,也相当于子容器也含有了,然后会启动子容器这时,就会进行真正的实例化。
  • 最终注入到LoadBalancerAutoConfiguration配置类的属性configurations,用于LoadBalancerClientFactory 的实例化
  • LoadBalancerClientFactory实例化的时候,就会获取LoadBalancerClientSpecification的对象了
    在这里插入图片描述在这里插入图片描述
    可以看到将LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration注入,包装成LoadBalancerClientSpecification类型

LoadBalancerClientFactory

再看一眼LoadBalancerClientFactorybean实例生成的过程
在这里插入图片描述
可以看到将LoadBalancerClientSpecification类型的LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration通过setConfiguations方法注入了进入

setConfiguations方法是在父类NamedContextFactory中执行的,稍微会分析NamedContextFactory,这里先分析LoadBalancerClientFactory 的结构

public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>implements ReactiveLoadBalancer.Factory<ServiceInstance> {private static final Log log = LogFactory.getLog(LoadBalancerClientFactory.class);/*** Property source name for load balancer.*/public static final String NAMESPACE = "loadbalancer";/*** Property for client name within the load balancer namespace.*/public static final String PROPERTY_NAME = NAMESPACE + ".client.name";private final LoadBalancerClientsProperties properties;public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {//记住这个LoadBalancerClientConfiguration,被当成了默认配置类注入到 NamedContextFactory ,也就是每个子容器都会有这个配置类super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);this.properties = properties;}public static String getName(Environment environment) {return environment.getProperty(PROPERTY_NAME);}@Overridepublic ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);}@Overridepublic LoadBalancerProperties getProperties(String serviceId) {if (properties == null) {if (log.isWarnEnabled()) {log.warn("LoadBalancerClientsProperties is null. Please use the new constructor.");}return null;}if (serviceId == null || !properties.getClients().containsKey(serviceId)) {// no specific client properties, return defaultreturn properties;}// because specifics are overlayed on top of defaults, everything in `properties`,// unless overridden, is in `clientsProperties`return properties.getClients().get(serviceId);}}

既然LoadBalancerClientConfiguration注入到NamedContextFactory中,我们就分析此配置类

LoadBalancerClientConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;/*** 怕读者忘了此配置的注入过程,这里再说一下* 上文说的LoadBalancerAutoConfiguration配置类中,创建了 LoadBalancerClientFactory 的bean对象,存在于父容器中* 在此bean创建的过程中,会通过构造方法将此配置LoadBalancerClientConfiguration转入到LoadBalancerClientFactory中* 然后会当做默认配置类注册到 NamedContextFactory 的子容器中,这样每个子容器都拥有* 我们也可以自己实现这个ReactorLoadBalancer类型的bean,覆盖此配置** */@Bean@ConditionalOnMissingBeanpublic 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)@ConditionalOnBlockingDiscoveryEnabled@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER + 1)public static class BlockingSupportConfiguration {//ServiceInstanceListSupplier来查询ServiceInstance服务列表,能看到这里是DiscoveryClient提供的。这样就和注册中心关联了@Bean@ConditionalOnBean(DiscoveryClient.class)@ConditionalOnMissingBean@Conditional(DefaultConfigurationCondition.class)public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(ConfigurableApplicationContext context) {return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching().build(context);}}//省略...}

LoadBalancerClientConfiguration的作用分析完了,在上文中

public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {//记住这个LoadBalancerClientConfiguration,被当成了默认配置类注入到 NamedContextFactory ,也就是每个子容器都会有这个配置类super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);this.properties = properties;
}

LoadBalancerClientConfiguration是传给了父类,LoadBalancerClientFactory 的结构

public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>implements ReactiveLoadBalancer.Factory<ServiceInstance> {..}

LoadBalancerClientFactory生成bean的过程中,调用完构造方法后,又执行了clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList)),此方法是在父类NamedContextFactory执行的

看一下clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList))执行结果
在这里插入图片描述

下面我们要分析父类NamedContextFactory,非常的重要

NamedContextFactory

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;/*** defaultConfigType是刚才文中说的子类LoadBalancerClientFactory创建时注入的。类型为LoadBalancerClientConfiguration* */public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {this.defaultConfigType = defaultConfigType;this.propertySourceName = propertySourceName;this.propertyName = propertyName;}@Overridepublic void setApplicationContext(ApplicationContext parent) throws BeansException {this.parent = parent;}public ApplicationContext getParent() {return parent;}/*** configurations为LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration,* 文中刚才分析过* */public void setConfigurations(List<C> configurations) {for (C client : configurations) {this.configurations.put(client.getName(), client);}}public Set<String> getContextNames() {return new HashSet<>(this.contexts.keySet());}@Overridepublic void destroy() {Collection<AnnotationConfigApplicationContext> values = this.contexts.values();for (AnnotationConfigApplicationContext context : values) {// This can fail, but it never throws an exception (you see stack traces// logged as WARN).context.close();}this.contexts.clear();}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);}protected AnnotationConfigApplicationContext createContext(String name) {AnnotationConfigApplicationContext context;//创建容器if (this.parent != null) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();if (parent instanceof ConfigurableApplicationContext) {beanFactory.setBeanClassLoader(((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());}else {beanFactory.setBeanClassLoader(parent.getClassLoader());}context = new AnnotationConfigApplicationContext(beanFactory);context.setClassLoader(this.parent.getClassLoader());}else {context = new AnnotationConfigApplicationContext();}//configurations就是LoadBalancerClientSpecification类型的LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration//这里是将@LoadBalancerClient对应的负载均衡配置注册到对应的容器中//由以上可知通过此步我们可以使用@LoadBalancerClient自定义负载均衡策略//如果不自定义的话,这里为falseif (this.configurations.containsKey(name)) {for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {context.register(configuration);}}//也就是将configurations中LoadBalancerClientSpecification类型的LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration注册到容器中//这样每个容器就拥有了for (Map.Entry<String, C> entry : this.configurations.entrySet()) {if (entry.getKey().startsWith("default.")) {for (Class<?> configuration : entry.getValue().getConfiguration()) {context.register(configuration);}}}//defaultConfigType就是LoadBalancerClientConfiguration,在子类LoadBalancerClientFactory的构造方法传入//在刚才分析LoadBalancerClientFactory的时候介绍过context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,Collections.<String, Object>singletonMap(this.propertyName, name)));//将父容器添加进去if (this.parent != null) {// Uses Environment from parent as well as beanscontext.setParent(this.parent);}context.setDisplayName(generateDisplayName(name));context.refresh();return context;}protected String generateDisplayName(String name) {return this.getClass().getSimpleName() + "-" + name;}/*** 每个LoadBalancerClientSpecification都创建一个AnnotationConfigApplicationContext* 也就是每个LoadBalancerClient会对应一个容器,其中的配置就对应容器中bean实例* */public <T> T getInstance(String name, Class<T> type) {//获取AnnotationConfigApplicationContext类型的容器AnnotationConfigApplicationContext context = getContext(name);try {//从容器中获取对应的实例return context.getBean(type);}catch (NoSuchBeanDefinitionException e) {// ignore}return null;}public <T> ObjectProvider<T> getLazyProvider(String name, Class<T> type) {return new ClientFactoryObjectProvider<>(this, name, type);}public <T> ObjectProvider<T> getProvider(String name, Class<T> type) {AnnotationConfigApplicationContext context = getContext(name);return context.getBeanProvider(type);}public <T> T getInstance(String name, Class<?> clazz, Class<?>... generics) {ResolvableType type = ResolvableType.forClassWithGenerics(clazz, generics);return getInstance(name, type);}@SuppressWarnings("unchecked")public <T> T getInstance(String name, ResolvableType type) {AnnotationConfigApplicationContext context = getContext(name);String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type);if (beanNames.length > 0) {for (String beanName : beanNames) {if (context.isTypeMatch(beanName, type)) {return (T) context.getBean(beanName);}}}return null;}public <T> Map<String, T> getInstances(String name, Class<T> type) {AnnotationConfigApplicationContext context = getContext(name);return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);}/*** Specification with name and configuration.*/public interface Specification {String getName();Class<?>[] getConfiguration();}}

到这里将每个@LoadBalancerClient都创建了AnnotationConfigApplicationContext的容器,然后放到了 LoadBalancerClientFactory

到这里bean的生成过程分析完毕,下一篇文章会分析整个执行过程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/87694.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Google FixMatch:SOTA 在半监督学习基准测试中的性能

作为当前计算机视觉应用的首选&#xff0c;深度网络通常通过监督学习&#xff08;一种需要标记数据集的方法&#xff09;来实现其强大的性能。尽管人工智能多年来取得了许多成就和进步&#xff0c;但标记数据的关键任务仍然落在人类专家身上。他们很难满足那些数据饥渴的深度网…

关于达梦网络通信异常问题

一.问题说明 springboot的项目&#xff0c;多数据源&#xff0c;其中一个数据源是达梦数据库。有个根据主键id查询详情的接口&#xff0c;一直报错网络通信异常&#xff0c;或连接尚未建立或者已经关闭。可以确保访问数据库的网络一切正常&#xff0c;单单一张表的接口一直报上…

基于模型的术语定义

文章仅供个人学习使用&#xff0c;请勿传播&#xff01; 原文来源&#xff1a; 袁亦方 大易方圆 OPM对象过程方法 2023-08-13 07:01 https://mp.weixin.qq.com/s/dUtuNLrMwFF_foCrQQyWmA INCOSE系统工程手册第5版使用说明部分&#xff08;内容对应第4版1.5节&#xff09;提出&…

登录验证码实现

Hutool代码改造 Hutool 有参考文档&#xff1b;很多工具类&#xff1b;把一些功能都封装好&#xff1b;都不用你自己去写&#xff1b;直接调用它的工具类 它这里会详细告诉你引入方式Hutool <dependency><groupId>cn.hutool</groupId><artifactId>hu…

数据结构:栈的实现(C实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》 文章目录 前言一、栈的实现思路1. 结构的定义2. 初始化栈(StackInit)3. 入栈(StackPush)4. 出栈(StackPop)5. 获取栈顶元素(StackTop)6. 检查栈是否为空(StackEmpty)7. 销毁栈(StackDestroy) 二、…

Von Maur, Inc EDI 需求分析

Von Maur, Inc 是一家历史悠久的卖场&#xff0c;成立于19世纪&#xff0c;总部位于美国。作为一家知名的零售商&#xff0c;Von Maur 主要经营高端时装、家居用品和美妆产品。其使命是为顾客提供优质的产品和无与伦比的购物体验。多年来&#xff0c;Von Maur 凭借其卓越的服务…

ubuntu网络管理

主机-ip&#xff0c;service—port 分别查看/etc/hosts&#xff0c;/etc/host.conf&#xff1b;/etc/services&#xff0c;/etc/resolv.conf&#xff1b; 内核更新——linux-image-generic 6.2.0-24.24 非常抱歉&#xff0c;我误解了你的问题。如果你想更新已安装的内核版本…

Android高通8.1 Selinux问题

1、最近客户提了一个需求&#xff0c;说要在user版本上面切分辨率&#xff0c;默认屏幕分辨率是2.5 k 执行adb shell指令之后变成 4k 然后adb shell wm size可以查看 2、一开始我能想到就是在文件节点添加权限&#xff0c;这里不管是mtk还是qcom&#xff08;高通平台&#xff…

深度剖析堆栈指针

为什么打印root的值与&root->value的值是一样的呢 测试结果&#xff1a; *号一个变量到底取出来的是什么&#xff1f; 以前我写过一句话&#xff0c;就是说&#xff0c;如果看到一个*变量&#xff0c;那就是直逼这个变量所保存的内存地址&#xff0c;然后取出里面保存的…

【C语言】每日一题---1

大家好&#xff0c;我是苏貝&#xff0c;本篇博客是系列博客每日一题的第一篇&#xff0c;本系列的题都不会太难&#xff0c;如果大家对这种系列的博客感兴趣的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 下面代码的结果是&#xff1a; #include <…

[保研/考研机试] KY7 质因数的个数 清华大学复试上机题 C++实现

描述 求正整数N(N>1)的质因数的个数。 相同的质因数需要重复计算。如1202*2*2*3*5&#xff0c;共有5个质因数。 输入描述&#xff1a; 可能有多组测试数据&#xff0c;每组测试数据的输入是一个正整数N&#xff0c;(1<N<10^9)。 输出描述&#xff1a; 对于每组数…

微服务01-SpringCloud

1、简介 SpringCloud集成了各种微服务功能组件&#xff0c;并基于SpringBoot实现了这些组件的自动装配&#xff0c;从而提供了良好的开箱即用体验。 其中常见的组件包括&#xff1a; 2、服务拆分和远程调用 2.1 服务拆分 这里总结了微服务拆分时的几个原则&#xff1a; …

卷积神经网络CNN

卷积神经网络CNN 1 应用领域1 检测任务2 分类和检索3 超分辨率重构4 医学任务5 无人驾驶6 人脸识别 2 卷积的作用3 卷积特征值计算方法4 得到特征图表示5 步长和卷积核大小对结果的影响1 步长2 卷积核 6 边缘填充方法7 特征图尺寸计算与参数共享8 池化层的作用9 整体网络架构10…

uniapp项目如何运行在微信小程序模拟器上

在HbuilderX中的小程序写完后自己一定要保存&#xff0c;否则会出不来效果 那么怎么让uniapp项目运行在微信小程序开发工具中呢 1 在hbuilderx中点击运行到小程序模拟器 2 然后在项目目录中会生成一个文件夹 在微信小程序开发软件中的工具>安全设置>打开端口 或者在微…

k8sday02

第四章 实战入门 本章节将介绍如何在kubernetes集群中部署一个nginx服务&#xff0c;并且能够对其进行访问。 Namespace ​ Namespace是kubernetes系统中的一种非常重要资源&#xff0c;它的主要作用是用来实现多套环境的资源隔离或者多租户的资源隔离。 ​ 默认情况下&…

Openlayers实战:选择feature,列表滑动,定位到相应的列表位置

在Openlayers的实际项目中,点击某个图层的feature,在左侧的列表中显示出来,滚动条滑动,能显示在视觉区内,具体的方法请参考源代码。 效果图 数据 guangdong.json https://geo.datav.aliyun.com/areas_v3/bound/440000_full.json 源代码 /* * @Author: 大剑师兰特(xia…

【设计模式】适配器模式

适配器模式&#xff08;Adapter Pattern&#xff09;是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式&#xff0c;它结合了两个独立接口的功能。 这种模式涉及到一个单一的类&#xff0c;该类负责加入独立的或不兼容的接口功能。举个真实的例子&#xff…

网页版Java(Spring/Spring Boot/Spring MVC)五子棋项目(四)对战模块

网页版Java&#xff08;Spring/Spring Boot/Spring MVC&#xff09;五子棋项目&#xff08;四&#xff09;对战模块 一、约定前后端交互接口1. 建立连接 的接口2. 针对落子的请求和响应 的接口 二、实现前端页面游戏大厅页面游戏大厅里的 java script 三、实现后端一. 建立各种…

品牌宣传与媒体传播是声誉管理的主要方式之一

企业声誉是现如今影响品牌信任度、客户忠诚度的重要因素&#xff0c;也被视为企业的一种无形资&#xff0c;更影响着企业未来的发展。因此&#xff0c;企业声誉管理也日渐成为企业管理的重要课题之一&#xff0c;尤其在品牌营销管理领域。 什么是声誉管理&#xff1f;声誉管理有…