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

  • 相关阅读:
    EBS SQL > Form & Report
    oracle sql 优化分析点
    MRP 物料需求计划
    MRPII 制造资源计划
    Barcode128 应用实务
    Oracle SQL语句优化技术分析
    APPSQLAP10710 Online accounting could not be created. AP Invoice 无法创建会计分录
    Oracle数据完整性和锁机制
    ORACLE Responsibility Menu Reference to Other User
    EBS 常用 SQL
  • 原文地址:https://www.cnblogs.com/wang-meng/p/12154955.html
Copyright © 2011-2022 走看看