@LoadBalanced注解RestTemplate拥有负载均衡的能力
关联阅读(必读)
回顾
当我在Ribbon的环境下使用RestTemplate发送请求时,通常我们会像下面这样注入一个restTemplate
@Autowired
@LoadBalanced
RestTemplate restTemplate;
为啥我们注入一个带有注解@LoadBalanced标注RestTemplate,此RestTemplate就具有负载均衡的能力,原理是什么呢?
猜测@LoadBalanced注解应该就是把这两点结合在了一起。
LoadBalancerAutoConfiguration配置类
这个整合剂,就是LoadBalancerAutoConfiguration配置类,
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
//注入所有使用@LoadBalanced的RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
// 对所有的RestTemplate使用RestTemplateCustomizer定制器进行统一处理
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
//LoadBalancerRequest 创建工厂
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
//LoadBalancerInterceptor 拦截器配置类
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// 负载均衡拦截器,看其参数传入的是loadBalancerClient
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
// RestTemplate定制器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
//省略在有RetryTemplate类情况下的分析。
}
@LoadBalanced
@LoadBalanced注解的作用是啥呢?看起源码,我们发现他自身也有一个注解@Qualifier
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
@Qualifier 我们应该认识,当容器内存在多个同类型的Bean实现类时,我们可以通过@Qualifier("service1")注解来标识,具体引入哪个。
此处的@LoadBalanced 其实就是@Qualifier的一种特殊形态。 当我们使用@LoadBalanced 标注一个Bean定义时,在自动注入的地方,也使用@LoadBalanced 来自动注入对应的Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
注入带有@LoadBalanced注解的RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
LoadBalancerInterceptor
负载均衡拦截器,有了这个拦截器,就可以设置到Restmplate上去,在请求发起之前做负载均衡操作,从多个候选应用中选择出一个。
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
// LoadBalancerClient 负载均衡客户端
private LoadBalancerClient loadBalancer;
// 用于构建出一个Request
private LoadBalancerRequestFactory requestFactory;
... // 省略构造函数(给这两个属性赋值)
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {
final URI originalUri = request.getURI();
String serviceName = originalUri.getHost();
Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);
return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));
}
}
可以看出LoadBalancerInterceptor 会调用loadBalancer#execute()方法做负载均衡,获取一个服务地址出来。并传入一个回调。
LoadBalancerRequestFactory类
public LoadBalancerRequest<ClientHttpResponse> createRequest(final HttpRequest request,
final byte[] body, final ClientHttpRequestExecution execution) {
//回掉方法。
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance, loadBalancer);
if (transformers != null) {
for (LoadBalancerRequestTransformer transformer : transformers) {
serviceRequest = transformer.transformRequest(serviceRequest, instance);
}
}
return execution.execute(serviceRequest, body);
};
}
当负载均衡选择出一个服务地址,apply回调方法,将当前HttpRequest 进行包装,重写其getURI()
@Override
public URI getURI() {
URI uri = this.loadBalancer.reconstructURI(
this.instance, getRequest().getURI());
return uri;
}
这样当真正发起请求时,获取的URI就是已经被负载均衡处理过的URI了。
RestTemplateCustomizer
RestTemplate定制器,用来对RestTemplate进行定制化操作,
此配置类注册的定制器,是用来对RestTemplate 设置LoadBalancerInterceptor的。
// RestTemplate定制器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
// 给RestTemplate 添加负载均衡拦截器
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
当然我们可以配置其他的RestTemplateCustomizer 来对RestTemplate做其他定制化操作。
而这些RestTemplateCustomizer 定制器,定制操作。统一由配置类中注册的SmartInitializingSingleton触发。
SmartInitializingSingleton
实现该接口类,当所有单例 bean 都初始化完成以后, 容器会回调该接口的方法 afterSingletonsInstantiated。
此配置类中SmartInitializingSingleton 做的操作就是:对哪些RestTemplate,执行哪些定制化操作
// 对所有的RestTemplate使用RestTemplateCustomizer定制器进行统一处理
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
也就说:spring在初始化过程后期,回调此配置类注册的SmartInitializingSingleton的afterSingletonsInstantiated,把上下文中的所有RestTemplateCustomizer 获取到,循环调用每个定制器的customize方法执行定制操作。其中就包括把LoadBalancerInterceptor设置到RestTemplate中。
至此:RestTemplate 就具有了负载均衡的能力。
总结
有@LoadBalanced 注解的RestTemplate,会被容器注入一个LoadBalancerInterceptor拦截器,从而使RestTemplate 具有负载均衡的能力。
讲完这节,Ribbon负载均衡与RestTemplate发送请求之间的知识点就形成了闭环。
推荐阅读:
欢迎大家关注我的公众号【源码行动】,最新个人理解及时奉送。

转载自:https://juejin.cn/post/6844904007794688007