cloud 客户端负载- @LoadBalanced 工作原理
问题
在 spring 中,为什么通过加入 @LoadBalanced
注解就可以实现客户端负载
@LoadBalanced 定义
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier //不同
public @interface LoadBalanced {
}
认真观查发现,这个注解比普通定义的注解的多了一个 @Qualifier
注解
LoadBalancerAutoConfiguration配置:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerProperties.class)
public class LoadBalancerAutoConfiguration {
//注入 加了@LoadBalanced注解的 RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@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);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory
loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@Conditional(RetryMissingOrDisabledCondition.class)
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor
loadBalancerInterceptor(LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer
restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list
= new ArrayList<>(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
//omit...
}
@LoadBalanced 工作原理
这里以 RestTemalate 为例
工作流程:
-
LoadBalancerRequestFactory 创建客户端负载 LoadBalancer
-
创建 LoadBalancerInterceptor , 用来进行客户端负载拦截
-
RestTemplateCustomizer 用来定制RestTemplate, 这里是为 RestTempate 加入 LoadBalancerInterceptor 拦截
-
SmartInitializingSingleton: 容器中注入的RestTempate ,使用 RestTemplateCustomizer 进行定制化处理,这里是为每个RestTemplate 加入 LoadBalancerInterceptor 拦截
流程都有了,那这里有一个问题 使用@LoadBalanced 注解后, 是如何,或者是什么时候被加载到容器中的?
在回答这个问题之前,我们先看看 @Qualifier 作用
@Qualifier 作用
一般的使用方式
- 定义一个Bean ,并指定名称为
aaa
- 使用时,通过@Qualifier 指定Bean 的名称,注入
aaa
//定义
@Bean("aaa")
public RestTemplate restTemplate(){
return new RestTemplate();
}
//调用方
@Autowired
@Qualifier("aaa")
private RestTemplate restTemplate;
当容器中有两个或者多个相同类型Bean的时候,如果想要依赖注入其中的一个,可以有两种做法
- 使用
@Resource
注解, 指定Bean的名称 - 使用 @Auwired 和 @Qualifer 搭配使用, @Autowired 默认是依赖注入的方式是 ByType , 当容器中有多个Bean 时, 如果仅仅使用 @Autowired 时会报错,@Autowired 不能区别到底使用哪一个Bean, 所以需要通过 @Qualifier 指定一个具体的Bean
- 当然也可以在定义Bean 的时候也使用上 , 如下
//定义
@Bean("aaa")
@Qualifier
public RestTemplate restTemplate(){
return new RestTemplate();
}
@Bean("bbb")
public RestTemplate restTemplate(){
return new RestTemplate();
}
//调用方
@RestController
public class IndexController {
@Autowired
@Qualifier
private List<RestTemplate> list = Collections.emptyList();
@Autowired
@Qualifier
private Map<String, RestTemplate> map = Collections.emptyMap();
@GetMapping("/index")
public String index(){
System.out.println(list.size());
System.out.println(map.size());
return "ok";
}
}
这里 的 list 大小就是 1, 即 @Autowired 只注入了@Qualifier 注解的Bean
看到这里, 我们的 @LoadBalanced
就有那么一点异曲同工之处了,只不过 @Qualifier
依附在 @LoadBalanced 注解之上了, 这也可以解释
public class LoadBalancerAutoConfiguration {
//就可以解释这里为什么要加 @LoadBalanced 注解了
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
}
回到我们的问题,自然迎刃而解了
good luck !