【一起學源碼-微服務】Ribbon 源碼二:通過Debug找出Ribbon初始化流程及ILoadBalancer原理分析

  • 2020 年 1 月 14 日
  • 筆記

前言

前情回顧

上一講講了Ribbon的基礎知識,通過一個簡單的demo看了下Ribbon的負載均衡,我們在RestTemplate上加了@LoadBalanced註解後,就能夠自動的負載均衡了。

本講目錄

這一講主要是繼續深入RibbonLoadBalancerClient和Ribbon+Eureka整合的方式。

上文我們已經知道調用RestTemplate時,會在其上面加上一個LoadBalancerInterceptor攔截器,其中會先執行LoadBalancerClient.execute()方法。

這裡我們會有一個疑問,默認的LoadBalancerInterceptor和LoadBalancerClient都是什麼呢?他們分別在哪裡進行初始化的呢?

帶著這些疑問我們來往前遞推下Ribbon初始化過程,相信看完下面的分析後,這些問題也就迎刃而解了。

目錄如下:

  1. 從XXXAutoConfig來追溯Ribbon初始化過程
  2. ZoneAwareLoadBalancer原理分析

說明

原創不易,如若轉載 請標明來源!

部落格地址:一枝花算不算浪漫 微信公眾號:壹枝花算不算浪漫

源碼閱讀

從XXXAutoConfig來追溯Ribbon初始化過程

在第一篇文章我們已經分析了,和LoadBalanced類同目錄下有一個LoadBalancerAutoConfiguration類,這個是我們最先找到的負載均衡自動配置類。

LoadBalancerAutoConfiguration作用

這個配置類主要是為調用的RestTemplate調用時添加LoadBalancerInterceptor過濾器,裡面還有其他一些重試的配置,這個後面再看。

查看此類的依賴,可以追蹤到:RibbonAutoConfiguration, 如圖所示:

RibbonAutoConfiguration作用
  1. 初始化SpringClientFactory
  2. 初始化LoadBalancerClient: RibbonLoadBalancerClient

其中在SpringClientFactory構造函數中有如下程式碼:

public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> {        public SpringClientFactory() {          super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name");      }  }

看到這裡實際上會初始化RibbonClientConfiguration配置類,接著往下看。

RibbonClientConfiguration作用
  1. 初始化ribbonRule: ZoneAvoidanceRule
  2. 初始化ribbonPing:DummyPing
  3. 初始化ribbonServerList:ConfigurationBasedServerList
  4. 初始化ServerListUpdater:new PollingServerListUpdater(config)
  5. 初始化ILoadBalancer:ZoneAwareLoadBalancer
  6. 初始化ribbonServerListFilter:ZonePreferenceServerListFilter
  7. 初始化ribbonLoadBalancerContext:RibbonLoadBalancerContext
  8. 初始化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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!

Tags: