【一起学源码-微服务】Ribbon 源码二:通过Debug找出Ribbon初始化流程及ILoadBalancer原理分析
前言
前情回顾
上一讲讲了Ribbon的基础知识,通过一个简单的demo看了下Ribbon的负载均衡,我们在RestTemplate上加了@LoadBalanced注解后,就能够自动的负载均衡了。
本讲目录
这一讲主要是继续深入
RibbonLoadBalancerClient和Ribbon+Eureka整合的方式。
上文我们已经知道调用
RestTemplate时,会在其上面加上一个
LoadBalancerInterceptor拦截器,其中会先执行
LoadBalancerClient.execute()方法。
这里我们会有一个疑问,默认的
LoadBalancerInterceptor和
LoadBalancerClient都是什么呢?他们分别在哪里进行初始化的呢?
带着这些疑问我们来往前递推下Ribbon初始化过程,相信看完下面的分析后,这些问题也就迎刃而解了。
目录如下:
- 从XXXAutoConfig来追溯Ribbon初始化过程
- ZoneAwareLoadBalancer原理分析
说明
原创不易,如若转载 请标明来源!
博客地址:一枝花算不算浪漫
微信公众号:壹枝花算不算浪漫
源码阅读
从XXXAutoConfig来追溯Ribbon初始化过程
在第一篇文章我们已经分析了,和
LoadBalanced类同目录下有一个
LoadBalancerAutoConfiguration类,这个是我们最先找到的负载均衡自动配置类。
LoadBalancerAutoConfiguration作用
这个配置类主要是为调用的
RestTemplate调用时添加
LoadBalancerInterceptor过滤器,里面还有其他一些重试的配置,这个后面再看。
查看此类的依赖,可以追踪到:
RibbonAutoConfiguration, 如图所示:
RibbonAutoConfiguration作用
- 初始化SpringClientFactory
- 初始化LoadBalancerClient: RibbonLoadBalancerClient
其中在
SpringClientFactory构造函数中有如下代码:
public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> { public SpringClientFactory() { super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name"); } }
看到这里实际上会初始化
RibbonClientConfiguration配置类,接着往下看。
RibbonClientConfiguration作用
- 初始化ribbonRule: ZoneAvoidanceRule
- 初始化ribbonPing:DummyPing
- 初始化ribbonServerList:ConfigurationBasedServerList
- 初始化ServerListUpdater:new PollingServerListUpdater(config)
- 初始化ILoadBalancer:ZoneAwareLoadBalancer
- 初始化ribbonServerListFilter:ZonePreferenceServerListFilter
- 初始化ribbonLoadBalancerContext:RibbonLoadBalancerContext
- 初始化serverIntrospector:DefaultServerIntrospector
最后总结为下面一张图所示:
ZoneAwareLoadBalancer原理分析
我们上面已经知道了Ribbon的大致流程,这里我们可以看到默认的
ILoadBalancer为
ZoneAwareLoadBalancer,还是回到之前
RibbonLoadBalancerClient.execute()方法中去,看下这里方法:
@Override public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException { ILoadBalancer loadBalancer = getLoadBalancer(serviceId); Server server = getServer(loadBalancer); if (server == null) { throw new IllegalStateException("No instances available for " + serviceId); } RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server, serviceId), serverIntrospector(serviceId).getMetadata(server)); return execute(serviceId, ribbonServer, request); }
这里第一行代码会获取一个
ILoadBalancer我们其实已经知道了,这里默认的
ILoadBalancer为
ZoneAwareLoadBalancer。
我们接着看下
RibbonLoadBalancerClient中的
getLoadBalancer()方法具体是怎么获取这个默认的LoadBalancer的。
这里面使用的是
SpringClientFactory.getLoadBalancer()方法,然后一直往里面跟, 最后调用到
NameContextFactory.java中:
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware { private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>(); public <T> T getInstance(String name, Class<T> type) { AnnotationConfigApplicationContext context = getContext(name); if (BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type).length > 0) { return context.getBean(type); } return null; } 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); } }
对每个服务名称,你要调用的每个服务,对应的服务名称,都有一个对应的spring的ApplicationContext容器,ServiceA对应着一个自己的独立的spring的ApplicationContext容器
比如说要获取这个ServiceA服务的LoadBalancer,那么就从ServiceCA服务对应的自己的ApplicationContext容器中去获取自己的LoadBalancer即可
如果是另外一个ServiceC服务,那么又是另外的一个spring APplicationContext,然后从里面获取到的LoadBalancer都是自己的容器里的LoadBalancer
可以通过debug 查看到下图返回的LoadBanlancer信息。这里就不在多赘述。
上面最后图片可以看到,实例化出来的instance是
ZoneAwareLoadBalancer, 这个类继承自
DynamicServerListLoadBalancer,顺带看下类结构:
到了这里就算是分析完了,再深究
ZoneAwareLoadBalancer就到了和Eureka整合相关的了,这一部分放到下一讲继续讲解了。
总结
用一张图做最后的总结:
申明
本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫
- Ambari-Server Rest API处理2(Ambari-Server通过Rest API进行服务安装、部署、操作流程+操作源码分析)
- Android OTA升级原理和流程分析(五)---update.zip包从上层进入Recovery服务
- Spring Core Container 源码分析三:Spring Beans 初始化流程分析
- nginx源码初读(12)--跟main一起看流程(Block 1: 初始化基础模块 Block 2:获取参数)
- 【一起学源码-微服务】Nexflix Eureka 源码九:服务续约源码分析
- 详细解读Volley(五)—— 通过源码来分析业务流程
- Nginx源码分析 - 主流程篇 - 全局变量cycle初始化
- android6.0源码分析之Camera API2.0下的初始化流程分析
- Ceilometer项目源码分析----ceilometer-alarm-evaluator服务的初始化和启动
- tomcat源码分析(一)初始化---Debug方式
- 通过uboot传参设置mtd分区流程源码分析
- 【微服务】服务发现:Eureka源码分析(一)基本流程
- Tomcat源码分析-初始化流程
- zookeeper服务发现实战及原理--spring-cloud-zookeeper源码分析
- Android系统原理与源码分析(1):利用Java反射技术阻止通过按钮关闭对话框
- Nouveau源码分析(五):NVIDIA设备初始化之nouveau_drm_load (2)
- android6.0源码分析之Camera API2.0下的初始化流程分析
- mybatis源码解析 - 通过一个简单查询例子分析流程
- Android OTA升级原理和流程分析(六)---Recovery服务流程细节
- Hbase 源码分析4 - Get 流程及rpc原理