上一講講了Ribbon的基礎知識,經過一個簡單的demo看了下Ribbon的負載均衡,咱們在RestTemplate上加了@LoadBalanced註解後,就可以自動的負載均衡了。java
這一講主要是繼續深刻RibbonLoadBalancerClient
和Ribbon+Eureka整合的方式。spring
上文咱們已經知道調用RestTemplate
時,會在其上面加上一個LoadBalancerInterceptor
攔截器,其中會先執行LoadBalancerClient.execute()
方法。微信
這裏咱們會有一個疑問,默認的LoadBalancerInterceptor
和LoadBalancerClient
都是什麼呢?他們分別在哪裏進行初始化的呢?負載均衡
帶着這些疑問咱們來往前遞推下Ribbon初始化過程,相信看完下面的分析後,這些問題也就迎刃而解了。ide
目錄以下:函數
原創不易,如若轉載 請標明來源!this
博客地址:一枝花算不算浪漫
微信公衆號:壹枝花算不算浪漫debug
在第一篇文章咱們已經分析了,和LoadBalanced
類同目錄下有一個LoadBalancerAutoConfiguration
類,這個是咱們最早找到的負載均衡自動配置類。code
這個配置類主要是爲調用的RestTemplate
調用時添加LoadBalancerInterceptor
過濾器,裏面還有其餘一些重試的配置,這個後面再看。server
查看此類的依賴,能夠追蹤到:RibbonAutoConfiguration
, 如圖所示:
其中在SpringClientFactory
構造函數中有以下代碼:
public class SpringClientFactory extends NamedContextFactory<RibbonClientSpecification> { public SpringClientFactory() { super(RibbonClientConfiguration.class, NAMESPACE, "ribbon.client.name"); } }
看到這裏實際上會初始化RibbonClientConfiguration
配置類,接着往下看。
最後總結爲下面一張圖所示:
咱們上面已經知道了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 和公衆號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小夥伴可關注我的公衆號:壹枝花算不算浪漫