Ribbon源码系列——负载均衡类体系与拦截器
再看@LoadBalanced注解
上一篇文章中我们看到过@LoadBalanced注解的源码:
我们发现这个注解上面有一行注释,指引我们去看LoadBalancerClient
类,我们就跟着这个线索去看一下
LoadBalancerClient负载均衡客户端
LoadBalancerClient
接口,继承自ServiceInstanceChooser
接口,ServiceInstanceChooser
提供了一个方法,可以通过服务ID选择一个具体的服务实例。这,这不就是我们负载均衡的意义么,传入一个服务标识,组件帮我选择一个适当的服务实例!
再来看LoadBalancerClient
接口本身提供的方法:
- execute:根据传入的服务ID和请求执行类,来执行一个具体的请求,返回请求结果
- reconstructURI:根据传入的服务实例和URI,返回一个具体host:port形式的URI
总结:LoadBalancerClient
这个接口提供的功能与我们研究的负载均衡的功能高度契合,我们有理由相信,这个类就是Ribbon的核心类。
LoadBalancerAutoConfiguration自动装配
之前我们全局搜索@LoadBalanced
注解的时候,注意到一个类注入了@LoadBalanced
修饰的RestTemplate,他就是LoadBalancerAutoConfiguration
类,我们知道在SpringBoot项目中,XXXAutoConfiguration
一般都用来将某个组件的配置,自动装配进Spring容器,所以我们有理由相信这个类是Ribbon自动装配的配置类:
我们可以看到,LoadBalancerAutoConfiguration
配置类帮我们注册了多个Bean,包括:
- LoadBalancerRequestFactory
- LoadBalancerInterceptor
- RestTemplateCustomizer
这个自动配置类中的Bean,大家刚接触的时候可能会直接懵掉,确实有点复杂。
Spring体系的源码都有这个特点,即:
- 类设计遵循单一职责原则
- 大量使用继承、多态
这样做的好处是单个类的职责非常清晰,看到接口或抽象类就基本可以理清功能。坏处是类体系复杂且庞大,对于初学者来说不太友好,遇到这种情况,笔者的经验是画类图,用自己的话来理解每个类的职责。下文会给出笔者画的图
整体类图梳理
笔者整理的LoadBalancerAutoConfiguration
自动装配的类图如下:
从图中可以看出来,负载均衡拦截器最终由负载均衡客户端构造出来,理论上可以具备负载均衡客户端的功能,即选择服务实例和执行请求。Spring通过RestTemplateCustomizer
定制器将拦截器定制到RestTemplate
中,这样就能完成对RestTemplate
的拦截了,我们合理猜想,负载均衡的功能就实现在拦截器中。
ClientHttpRequestInterceptor拦截器
SpringBoot提供了ClientHttpRequestInterceptor
拦截器接口,实现这个拦截器接口的intercept
方法可以对通过RestTemplate
发起的请求和响应做一些拦截性的处理。通常请求是这样被处理的:
- 执行拦截器对request的拦截
- 执行http 请求或直接返回
- 执行拦截器对response的拦截
我们来看一下具体的实现类LoadBalancerInterceptor
的源码:
在红杠的部分可以看到,拦截器最后正是调用了LoadBalancerClient#execute
完全拦截了RestTemplate
的原有请求。
本篇文章先到这里,总结一下:本文主要梳理了LoadBalancerAutoConfiguration
注入到Spring容器中的类整体体系,最终发现是通过LoadBalancerInterceptor
拦截器,调用了LoadBalancerClient#execute
拦截了RestTemplate
的原有请求逻辑,完成了负载均衡的功能。
Over🥽