0


Ribbon源码深度解析

① 目前,我看的Ribbon的源码版本是spring-cloud-netflix-ribbon-2.2.6.RELEASE,但是网上没有找到该版本源代码,只能查看jar下编译后的代码,方法的跳转和搜索不太方便…,以上是题外话,继续:首先可以找到META-INF/spring.factories文件,查看该文件中配置了哪些自动装配类,刚好只有一个,如下图所示:
在这里插入图片描述
② 进入RibbonAutoConfiguration类中,查看整体结构,如下图所示:
在这里插入图片描述
比较核心的类有这么几个:
SpringClientFactory:提供了SpringClientFactory#getInstance()方法,可以获取 Ribbon的一些组件,如IClient、ILoadBalancer、IClientConfig等。
LoadBalancerClient:Ribbon用于发起远程调用,
Spring在实例化RibbonAutoConfiguration之前,会先加载LoadBalancerAutoConfiguration类,因为它是被@AutoConfigureBefore注解所修饰的,再看看LoadBalancerAutoConfiguration类,如下图所示:
在这里插入图片描述
在LoadBalancerAutoConfiguration类中,有一个属性注入:restTemplates,该成员属性实际上是被@LoadBalanced和@Autowired(required = false) 注解共同修饰,意思是在Spring容器中找到所有的RestTemplate,并且被注入的RestTemplate必须也是被@LoadBalanced注解修饰才行。因此,我们如果自己注入的RestTemplate想要有负载均衡作用,必须加上@LoadBalanced注解。
再具体说说为什么我们自己注入的RestTemplate加上@LoadBalanced就可以实现负载均衡的功能:在LoadBalancerAutoConfiguration类中,还有一个类,当然它是一段λ表达式,实际上它也是SmartInitializingSingleton接口的实现类SmartInitializingSingleton#afterSingletonsInstantiated()方法,该方法在Spring实例化了所有的单例bean之后,会调用该方法。也就是在LoadBalancerAutoConfiguration#loadBalancedRestTemplateInitializerDeprecated()方法中,注入了List restTemplateCustomizers方法入参,遍历restTemplateCustomizers,调用 RestTemplateCustomizer#customize()方法,传入RestTemplate对象(其中也就包括我们自己定义的RestTemplate对象),对RestTemplate对象做处理,加入请求的拦截器(算是一种“增强“),如下图所示:
在这里插入图片描述
继续往下看,在LoadBalancerAutoConfiguration类中,其实就注入了RestTemplateCustomizer对象,它其实也是一段λ表达式,在这段λ表达式中只干了一件事:往RestTemplate中添加了一个LoadBalancerInterceptor,看名字,就知道它才是实现负债均衡最核心的功能(如下如所示):
在这里插入图片描述
并且,在注入LoadBalancerInterceptor的时候,实际上是调用了它的有参构造,传入了两个参数,即:LoadBalancerClient和LoadBalancerRequestFactory,看看LoadBalancerInterceptor类,如下图所示:
在这里插入图片描述
而LoadBalancerClient类,实际上是在RibbonAutoConfiguration类中注入的,如下图所示:
在这里插入图片描述
③ 这样的话,整个链路就很清晰:我们在使用我们自己定义的RestTemplate的时候,只要加上@LoadBalanced注解,Spring就会拿到我们定义的RestTemplate对象,再从Spring容器中拿到LoadBalancerInterceptor对象,并且加到RestTemplate的成员属性interceptors中,最终LoadBalancerInterceptor就会实现客户端的负载均衡功能,当然最终的实现,是依赖于LoadBalancerClient类。
④ 具体看看调用链路,以RestTemplate#getForObject()方法为例:具体看图:
在这里插入图片描述
再看看RestTemplate#execute()方法:
在这里插入图片描述
再看看RestTemplate#doExecute()方法:
在这里插入图片描述
先看一下RestTemplate#createRequest()方法:
在这里插入图片描述
createRequest ()方法实际上是调用RestTemplate父类HttpAccessor#createRequest ()方法,再看看HttpAccessor#getRequestFactory()方法,具体如下图所示:
在这里插入图片描述
在该方法中,会创建InterceptingClientHttpRequestFactory,并且传入interceptors,其中,interceptors就包含了之前注入的LoadBalancerInterceptor对象。回到InterceptingHttpAccessor父类HttpAccessor#createRequest()方法中:
在这里插入图片描述
查看AbstractClientHttpRequestFactoryWrapper#createRequest()方法,它实际上是抽象方法,具体实现在其实现类中,即InterceptingClientHttpRequestFactory:
在这里插入图片描述
再看看InterceptingClientHttpRequestFactory#createRequest()方法:
在这里插入图片描述
最终返回的是InterceptingClientHttpRequest对象,并且传入了interceptors。再回到RestTemplate#doExecute()方法,如下图所示:
在这里插入图片描述
再看看AbstractClientHttpRequest#execute()方法:
在这里插入图片描述
再看看AbstractClientHttpRequest#executeInternal()方法:
在这里插入图片描述
再看看AbstractBufferingClientHttpRequest#executeInternal()方法,这是一个抽象方法,具体看实现类,由上文可知,实际上就是InterceptingClientHttpRequest类,如下图所示:
在这里插入图片描述
再看看InterceptingClientHttpRequest#executeInternal()方法:
在这里插入图片描述
由上图可知,interceptors是不为空的,因此,遍历interceptors,最终会调用到LoadBalancerInterceptor#intercept()方法,如下图所示:
在这里插入图片描述
最终调用的是RibbonLoadBalancerClient#execute()方法,如下图所示:
在这里插入图片描述
后续调用到的RibbonLoadBalancerClient#execute()方法,其它的重载方法就不用再看了,无非是拿到了Server后,拿到ip/port,进行地址以及请求体的拼接,最终发起远程HTTP的调用,拿到Response返回罢了。我们核心要看的当然是RibbonLoadBalancerClient#getServer()方法,看其是如何得到一个服务节点进行调用的:
在这里插入图片描述
再看ZoneAwareLoadBalancer#chooseServer()方法,为啥是ZoneAwareLoadBalancer类而不是其他的呢,具体看RibbonClientConfiguration配置类可知:
在这里插入图片描述
接着上文,继续看ZoneAwareLoadBalancer#chooseServer()方法,如下如所示:
在这里插入图片描述
这里的ZoneAwareLoadBalancer.getLoadBalancerStats().getAvailableZones().size() 是不大于1的,所以看ZoneAwareLoadBalancer父类的chooseServer()方法:
在这里插入图片描述
会发现,调用到了this.rule.choose()方法。这个有默认的rule,具体也是看RibbonClientConfiguration配置类,如果我们用Nacos做注册中心,则可以注入NacosRule类到Spring中去,如果是这个类的话,看NacosRule#choose()方法:
在这里插入图片描述
以上,就是ribbon源码的简单解析,如有错误,恳请批评指正!


本文转载自: https://blog.csdn.net/weixin_41338970/article/details/135945652
版权归原作者 weixin_lizhao 所有, 如有侵权,请联系我们删除。

“Ribbon源码深度解析”的评论:

还没有评论