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


前言

前情回顧

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

本講目錄

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

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

這里我們會有一個疑問,默認的LoadBalancerInterceptorLoadBalancerClient都是什么呢?他們分別在哪里進行初始化的呢?

帶着這些疑問我們來往前遞推下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

最后總結為下面一張圖所示:

22.png

ZoneAwareLoadBalancer原理分析

我們上面已經知道了Ribbon的大致流程,這里我們可以看到默認的ILoadBalancerZoneAwareLoadBalancer,還是回到之前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 我們其實已經知道了,這里默認的ILoadBalancerZoneAwareLoadBalancer

我們接着看下 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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!

感興趣的小伙伴可關注個人公眾號:壹枝花算不算浪漫

22.jpg


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM