前言
前情回顧
上一講講了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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小伙伴可關注個人公眾號:壹枝花算不算浪漫