【一起學源碼-微服務】Ribbon 源碼二:通過Debug找出Ribbon初始化流程及ILoadBalancer原理分析
- 2020 年 1 月 14 日
- 筆記
前言
前情回顧
上一講講了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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
