@LoadBalanced注解在生产环境使用的不太多,主要是springcloud项目,访问下游服务的时候,用服务名称访问,并使用负载策略,但是实际生产的时候我们一般使用feign访问下游服务
@LoadBalanced的使用,RestTemplate用LoadBalanced修饰之后,就可以通过服务名称访问服务,并使用负载均衡策略,默认是轮询策略
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
点开@LoadBalanced 注解发现
image.png
其实就是Qualifier注解,那何为Qualifier呢,是spring的注解
@Component
public class QualifierTestService {
@Autowired
@Qualifier
List<TestQualifier> testQualifierList;
@PostConstruct
public void test() {
System.out.println ("QualifierTestService---");
for (TestQualifier testQualifier : testQualifierList) {
System.out.println (testQualifier.getName ());
}
}
}
@Component
public class QualifierTestService1 {
@Autowired
List<TestQualifier> testQualifierList;
@PostConstruct
public void test() {
System.out.println ("QualifierTestService1---");
for (TestQualifier testQualifier : testQualifierList) {
System.out.println (testQualifier.getName ());
}
}
}
@Data
public class TestQualifier {
private String name;
public void hello() {
}
}
@Configuration
public class TestQualifierAutoConfig {
@Bean
@Qualifier
public TestQualifier getTestQualifier1(){
TestQualifier testQualifier = new TestQualifier ();
testQualifier.setName ("TestQualifier1");
return testQualifier;
}
@Bean
public TestQualifier getTestQualifier2(){
TestQualifier testQualifier = new TestQualifier ();
testQualifier.setName ("TestQualifier2");
return testQualifier;
}
}
打印结果
QualifierTestService---
TestQualifier1
QualifierTestService1---
TestQualifier1
TestQualifier2
总结:
Qualifier标注的bean,可以被Autowired引用到,如果Autowired和Qualifier配合使用,只能获取到标注了Qualifier的bean
介绍完Qualifier,回到LoadBalanced注解分析
首先是自动装配
image.png
LoadBalancerAutoConfiguration类下的重要方法
//获取标注了@LoadBalanced注解的RestTemplate
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
//入参为ObjectProvider<List<RestTemplateCustomizer>>
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
//这里的restTemplates就是标注了@LoadBalanced的RestTemplate
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
ObjectProvider<List<RestTemplateCustomizer>>作为入参,如何被注入到容器
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
//将拦截器放到restTemplate中,这样就实现了
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
以上的三个代码块都在LoadBalancerAutoConfiguration类中,
这个RestTemplateCustomizer是一个函数性接口,在loadBalancedRestTemplateInitializerDeprecated方法中执行,
而loadBalancedRestTemplateInitializerDeprecated返回的SmartInitializingSingleton依然是函数性接口,
那SmartInitializingSingleton是如何被执行,这里涉及到了spring源码
org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
这个方法的第二个for循环就是,第一个for循环实例化所有的bean,这里就有个问题,如果用 @PostConstruct注解修饰的方法中
用RestTemplate通过微服务名称调用服务的话,是有问题的,因为@PostConstruct会在实例化bean的时候执行,而此时第二个for循环
没有被调用,也就是loadBalancerInterceptor没有加载进RestTemplate中,通过服务名称访问是有问题的.
网友评论