上一讲讲了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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注我的公众号:壹枝花算不算浪漫