Ribbon源码系列——负载均衡类体系与拦截器

再看@LoadBalanced注解

上一篇文章中我们看到过@LoadBalanced注解的源码:

image-20210702152733813

我们发现这个注解上面有一行注释,指引我们去看LoadBalancerClient类,我们就跟着这个线索去看一下

LoadBalancerClient负载均衡客户端

image-20210702153039371

image-20210702153056852

LoadBalancerClient接口,继承自ServiceInstanceChooser接口,ServiceInstanceChooser提供了一个方法,可以通过服务ID选择一个具体的服务实例。这,这不就是我们负载均衡的意义么,传入一个服务标识,组件帮我选择一个适当的服务实例!

再来看LoadBalancerClient接口本身提供的方法:

  • execute:根据传入的服务ID和请求执行类,来执行一个具体的请求,返回请求结果
  • reconstructURI:根据传入的服务实例和URI,返回一个具体host:port形式的URI

总结:LoadBalancerClient这个接口提供的功能与我们研究的负载均衡的功能高度契合,我们有理由相信,这个类就是Ribbon的核心类。

LoadBalancerAutoConfiguration自动装配

之前我们全局搜索@LoadBalanced注解的时候,注意到一个类注入了@LoadBalanced修饰的RestTemplate,他就是LoadBalancerAutoConfiguration类,我们知道在SpringBoot项目中,XXXAutoConfiguration一般都用来将某个组件的配置,自动装配进Spring容器,所以我们有理由相信这个类是Ribbon自动装配的配置类:

image-20210702162109416

我们可以看到,LoadBalancerAutoConfiguration配置类帮我们注册了多个Bean,包括:

  • LoadBalancerRequestFactory
  • LoadBalancerInterceptor
  • RestTemplateCustomizer

这个自动配置类中的Bean,大家刚接触的时候可能会直接懵掉,确实有点复杂。


Spring体系的源码都有这个特点,即:

  • 类设计遵循单一职责原则
  • 大量使用继承、多态

这样做的好处是单个类的职责非常清晰,看到接口或抽象类就基本可以理清功能。坏处是类体系复杂且庞大,对于初学者来说不太友好,遇到这种情况,笔者的经验是画类图,用自己的话来理解每个类的职责。下文会给出笔者画的图

整体类图梳理

笔者整理的LoadBalancerAutoConfiguration自动装配的类图如下:

Ribbon自动装配类图

从图中可以看出来,负载均衡拦截器最终由负载均衡客户端构造出来,理论上可以具备负载均衡客户端的功能,即选择服务实例和执行请求。Spring通过RestTemplateCustomizer定制器将拦截器定制到RestTemplate中,这样就能完成对RestTemplate的拦截了,我们合理猜想,负载均衡的功能就实现在拦截器中。

ClientHttpRequestInterceptor拦截器

SpringBoot提供了ClientHttpRequestInterceptor拦截器接口,实现这个拦截器接口的intercept方法可以对通过RestTemplate发起的请求和响应做一些拦截性的处理。通常请求是这样被处理的:

  1. 执行拦截器对request的拦截
  2. 执行http 请求或直接返回
  3. 执行拦截器对response的拦截

我们来看一下具体的实现类LoadBalancerInterceptor的源码:

image-20210702164044837

在红杠的部分可以看到,拦截器最后正是调用了LoadBalancerClient#execute完全拦截了RestTemplate的原有请求。


本篇文章先到这里,总结一下:本文主要梳理了LoadBalancerAutoConfiguration注入到Spring容器中的类整体体系,最终发现是通过LoadBalancerInterceptor拦截器,调用了LoadBalancerClient#execute拦截了RestTemplate的原有请求逻辑,完成了负载均衡的功能。

Over🥽

posted @ 2021-07-02 16:51  孔令翰  阅读(198)  评论(0编辑  收藏  举报