zoukankan      html  css  js  c++  java
  • 【一起学源码-微服务】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

  • 相关阅读:
    Oracle数据库基础
    2016-08-08二期模拟考试
    易买网-登入
    常量接口模式
    反射
    Hhibernate延迟加载
    URL和URI的区别和联系
    Socket编程
    ArrayList如何实现线程安全
    移位运算符
  • 原文地址:https://www.cnblogs.com/wang-meng/p/12154955.html
Copyright © 2011-2022 走看看