专栏首页一枝花算不算浪漫的专栏【一起学源码-微服务】Ribbon 源码二:通过Debug找出Ribbon初始化流程及ILoadBalancer原理分析

【一起学源码-微服务】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

最后总结为下面一张图所示:

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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • [读书笔记]C#学习笔记三: C#类型详解..

    一枝花算不算浪漫
  • MyBatis学习总结(三)——优化MyBatis配置文件中的配置

    一枝花算不算浪漫
  • Mybatis逆向工程构建项目实例.

    一枝花算不算浪漫
  • 文章马伊琍离婚后微博评论太多了...用代码来解决吧

    上周末文章同学的一条微博:“吾愛伊琍,同行半路,一别两宽,餘生漫漫,依然親情守候.”

    Python编程与实战
  • 安静100分钟理解js面向对象

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head>...

    前朝楚水
  • 功能解说 | 小白必看!只要1分钟,快速生成小程序

    点击蓝字 ? 关注企点 ? 依靠微信这个大流量平台,小程序从推出之初,就备受关注。其“无需安装,用完就走”的特性,也越来越受到用户的欢迎。 那么不懂代码的商...

    腾讯企点
  • Python局部变量与全局变量区别原理解析

    在子程序中定义的变量称为局部变量,在程序的一开始定义的变量称为全局变量。 全局变量作用域是整个程序,局部变量作用域是定义该变量的子程序。 当全局变量与局部变...

    砸漏
  • ClassLoader

    如下图所示,JVM类加载机制分为五个部分:加载,验证,准备,解析,初始化,下面我们就分别来看一下这五个过程。

    大学里的混子
  • c#中的可空类型和空合并操作符(Nullable Types 和 Null Coalescing Operator)

    程序你好
  • SpringBoot系列教程web篇之Get请求参数解析姿势汇总

    一般在开发web应用的时候,如果提供http接口,最常见的http请求方式为GET/POST,我们知道这两种请求方式的一个显著区别是GET请求的参数在url中,...

    一灰灰blog

扫码关注云+社区

领取腾讯云代金券