LoadBalanced注解

183 阅读2分钟

小知识,大挑战!本文正在参与「程序员必备小知识」创作活动

LoadBalanced注解

spring-cloud-commons模块中的META-INF/spring.factories文件中存在LoadBalancerAutoConfiguration自动配置类,根据工厂加载机制会被ApplicationContext加载。

LoadBalancerAutoConfiguration:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

   @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)
   @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
   static class LoadBalancerInterceptorConfig {

      @Bean
      public LoadBalancerInterceptor ribbonInterceptor(
            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);
         };
      }

   }

   /**
    * Auto configuration for retry mechanism.
    */
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(RetryTemplate.class)
   public static class RetryAutoConfiguration {

      @Bean
      @ConditionalOnMissingBean
      public LoadBalancedRetryFactory loadBalancedRetryFactory() {
         return new LoadBalancedRetryFactory() {
         };
      }

   }

   /**
    * Auto configuration for retry intercepting mechanism.
    */
   @Configuration(proxyBeanMethods = false)
   @ConditionalOnClass(RetryTemplate.class)
   public static class RetryInterceptorAutoConfiguration {

      @Bean
      @ConditionalOnMissingBean
      public RetryLoadBalancerInterceptor ribbonInterceptor(
            LoadBalancerClient loadBalancerClient,
            LoadBalancerRetryProperties properties,
            LoadBalancerRequestFactory requestFactory,
            LoadBalancedRetryFactory loadBalancedRetryFactory) {
         return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
               requestFactory, loadBalancedRetryFactory);
      }

      @Bean
      @ConditionalOnMissingBean
      public RestTemplateCustomizer restTemplateCustomizer(
            final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
         return restTemplate -> {
            List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                  restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
         };
      }

   }

}
  1. restTemplates获取ApplicationContext中所有被@LoadBalanced注解修饰的RestTemplate
  2. restTemplateCustomizers是ApplicationContext存在的RestTemplateCustomizer Bean的集合
  3. 然后遍历restTemplates,使用RestTemplateCustomizer集合给每个RestTemplate定制。

它的内部类LoadBalancerInterceptorConfig配置类中定义了RestTemplateCustomizer

  1. @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")表示不存在RetryTemplate时才会生效。
  2. 定义LoadBalancerInterceptor Bean,这个拦截器实现ClientHttpRequestInterceptor接口,可以被添加到RestTemplate的拦截器列表中
  3. 定义RestTemplateCustomizer Bean
  4. 使用lambda表达式在RestTemplate的拦截器列表中添加LoadBalancerInterceptor拦截器

RetryLoadBalancerInterceptor比LoadBalancerInterceptor,在RestTemplate调用失败的情况下进行重试操作

所以@LoadBalanced注解直接修饰RestTemplate会被添加一个LoadBalancerInterceptor拦截器

LoadBalancerInterceptor:

public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {

   private LoadBalancerClient loadBalancer;

   private LoadBalancerRequestFactory requestFactory;

   public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
         LoadBalancerRequestFactory requestFactory) {
      this.loadBalancer = loadBalancer;
      this.requestFactory = requestFactory;
   }

   public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
      // for backwards compatibility
      this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
   }

   @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));
   }

}
  1. LoadBalancerInterceptor需要LoadBalancerClient参数和LoadBalancerRequestFactory参数,LoadBalancerClient根据负载请求和服务名做真正服务的调用,LoadBalancerRequestFactory构造LoadBalancerRequest,构造过程中使用LoadBalancerRequestTransformer对请求做一些自定义的转换操作
  2. originalUri.getHost();表示使用URI中的host信息
  3. 使用LoadBalancerClient客户端负载均衡器做真正的服务调用