@LoadBalanced注解

2022-08-15  本文已影响0人  念䋛

@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中,通过服务名称访问是有问题的.

上一篇 下一篇

猜你喜欢

热点阅读