【一起学源码-微服务】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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫

【一起学源码-微服务】Ribbon 源码二:通过Debug找出Ribbon初始化流程及ILoadBalancer原理分析的更多相关文章
- 【一起学源码-微服务】Ribbon源码五:Ribbon源码解读汇总篇~
前言 想说的话 [一起学源码-微服务-Ribbon]专栏到这里就已经全部结束了,共更新四篇文章. Ribbon比较小巧,这里是直接 读的spring cloud 内嵌封装的版本,里面的各种config ...
- 【一起学源码-微服务】Eureka+Ribbon+Feign阶段性总结
前言 想说的话 这里已经梳理完Eureka.Ribbon.Feign三大组件的基本原理了,今天做一个总结,里面会有一个比较详细的调用关系流程图. 说明 原创不易,如若转载 请标明来源! 博客地址:一枝 ...
- 【一起学源码-微服务】Nexflix Eureka 源码十:服务下线及实例摘除,一个client下线到底多久才会被其他实例感知?
前言 前情回顾 上一讲我们讲了 client端向server端发送心跳检查,也是默认每30钟发送一次,server端接收后会更新注册表的一个时间戳属性,然后一次心跳(续约)也就完成了. 本讲目录 这一 ...
- 【一起学源码-微服务】Nexflix Eureka 源码十三:Eureka源码解读完结撒花篇~!
前言 想说的话 [一起学源码-微服务-Netflix Eureka]专栏到这里就已经全部结束了. 实话实说,从最开始Eureka Server和Eureka Client初始化的流程还是一脸闷逼,到现 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
首先感谢张队@geffzhang公众号转发了上一篇文章,希望广大.neter多多推广dapr,让云原生更快更好的在.net这片土地上落地生根. 目录:一.通过Dapr实现一个简单的基于.net的微服务 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
今天这篇博文的主要目的是分享一下我设计Saga的实现思路来抛砖引玉,其实Saga本身非常的类似于一个简单的工作流体系,相比工作流不一样的部分在于它没有工作流的复杂逻辑处理机制(比如会签),没有条件分支 ...
- 【一起学源码-微服务】Ribbon 源码一:Ribbon概念理解及Demo调试
前言 前情回顾 前面文章已经梳理清楚了Eureka相关的概念及源码,接下来开始研究下Ribbon的实现原理. 我们都知道Ribbon在spring cloud中担当负载均衡的角色, 当两个Eureka ...
- 【一起学源码-微服务】Ribbon 源码三:Ribbon与Eureka整合原理分析
前言 前情回顾 上一篇讲了Ribbon的初始化过程,从LoadBalancerAutoConfiguration 到RibbonAutoConfiguration 再到RibbonClientConf ...
- 【一起学源码-微服务】Ribbon 源码四:进一步探究Ribbon的IRule和IPing
前言 前情回顾 上一讲深入的讲解了Ribbon的初始化过程及Ribbon与Eureka的整合代码,与Eureka整合的类就是DiscoveryEnableNIWSServerList,同时在Dynam ...
随机推荐
- js this详解
This的定义: 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用. this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是 ...
- Python深入:Distutils发布Python模块
Distutils可以用来在Python环境中构建和安装额外的模块.新的模块可以是纯Python的,也可以是用C/C++写的扩展模块,或者可以是Python包,包中包含了由C和Python编写的模块. ...
- oracle函数 power(x,y)
[功能]返回x的y次幂 [参数]x,y 数字型表达式 [返回]数字 [示例] select power(2.5,2),power(1.5,0),power(20,-1) from dual; 返回:6 ...
- LRJ-Example-06-13-Uva1103
pic[][]数组存储每个点的值,0或1,输入时在原图的周围加了一圈0. color[][]数组存储每个点的color值,从1开始,dfs(row, col, c) 负责对每个点着色,连通在一起的连通 ...
- H3C 802.11无线网络的介质访问控制
- hadoop2.6.0 + hbase-1.0.0 伪分布配置
1 基本配置 主机名: 192.168.145.154 hadoop2 ======= 2 etc/hadoop下文件配置 1)core-site.xml <configuration> ...
- HDU 1596 也是最小路径Dijkstra
#include<cstdio> #include<cmath> #include<cstring> +; double dist[qq]; double city ...
- NLP --- 条件随机场CRF详解 重点 特征函数 转移矩阵
上一节我们介绍了CRF的背景,本节开始进入CRF的正式的定义,简单来说条件随机场就是定义在隐马尔科夫过程的无向图模型,外加可观测符号X,这个X是整个可观测向量.而我们前面学习的HMM算法,默认可观测符 ...
- codeforces 615A
题意:给你m个编号为1到m的灯泡:然后n行中每一行的第一个数给出打开灯泡的个数xi 然后是yij是每个灯泡的编号: 题目中有一句话. 我愣是没看,因为我英语真的是一窍不通,看了也白看,直接看数据做的, ...
- java面向接口编程之制定标准和简单工厂模式
制定一个标准,让别人去实现或者说满足它! Eg: interface USB{//定义USB标准 void useUSB();//USB有使用USB的行为 } 简单工厂模式 构建一个工厂出来,在里面进 ...