1. 程式人生 > >@LoadBalanced註解使用的理解

@LoadBalanced註解使用的理解

在使用springcloud ribbon客戶端負載均衡的時候,可以給RestTemplate bean 加一個@LoadBalanced註解,就能讓這個RestTemplate在請求時擁有客戶端負載均衡的能力:

@Bean
@LoadBalanced //開啟負載均衡的功能
RestTemplate restTemplate() {
    return new RestTemplate();
}

@LoadBalanced的註解原始碼:

/**
 * Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
 * @author Spencer Gibb
 */
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}

關於@Qulifier註解作用自行百度。

LoadBalancerAutoConfiguration是為實現客戶端負載均衡器的自動裝配類:

/**
 * Auto configuration for Ribbon (client side load balancing).
 *
 * @author Spencer Gibb
 * @author Dave Syer
 * @author Will Tran
 */
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {

   @LoadBalanced
   @Autowired(required = false)
   private List<RestTemplate> restTemplates = Collections.emptyList();

   @Bean
   public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
         final List<RestTemplateCustomizer> customizers) {
      return new SmartInitializingSingleton() {
         @Override
         public void afterSingletonsInstantiated() {
            for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
               for (RestTemplateCustomizer customizer : customizers) {
                  customizer.customize(restTemplate);
               }
            }
         }
      };
   }

   @Autowired(required = false)
   private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();

   @Bean
   @ConditionalOnMissingBean
   public LoadBalancerRequestFactory loadBalancerRequestFactory(
         LoadBalancerClient loadBalancerClient) {
      return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
   }

   @Configuration
   @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 new RestTemplateCustomizer() {
            @Override
            public void customize(RestTemplate restTemplate) {
               List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                     restTemplate.getInterceptors());
               list.add(loadBalancerInterceptor);
               restTemplate.setInterceptors(list);
            }
         };
      }
   }

   @Configuration
   @ConditionalOnClass(RetryTemplate.class)
   public static class RetryAutoConfiguration {
      @Bean
      public RetryTemplate retryTemplate() {
         RetryTemplate template =  new RetryTemplate();
         template.setThrowLastExceptionOnExhausted(true);
         return template;
      }

      @Bean
      @ConditionalOnMissingBean
      public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() {
         return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
      }
   }

   @Configuration
   @ConditionalOnClass(RetryTemplate.class)
   public static class RetryInterceptorAutoConfiguration {
      @Bean
      @ConditionalOnMissingBean
      public RetryLoadBalancerInterceptor ribbonInterceptor(
            LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
            LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
            LoadBalancerRequestFactory requestFactory) {
         return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
               lbRetryPolicyFactory, requestFactory);
      }

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

從LoadBalancerAutoConfiguration類註解可以知道,負載均衡自動配置需要ConditionalOnClass(RestTemplate.class)@ConditionalOnBean(LoadBalancerClient.class)

這裡直接解釋下為什麼@LoadBalanced註解能讓RestTemplate在請求時擁有客戶端負載均衡的能力。LoadBalancerAutoConfiguration類會產生一個SmartInitializingSingleton的Bean:

@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
      final List<RestTemplateCustomizer> customizers) {
   return new SmartInitializingSingleton() {
      @Override
      public void afterSingletonsInstantiated() {
         for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
            for (RestTemplateCustomizer customizer : customizers) {
               customizer.customize(restTemplate);
            }
         }
      }
   };
}

LoadBalancerAutoConfiguration.this.restTemplates即所有被@LoadBalanced註解的RestTemplate,這裡的customizers如下:

   @Bean
   @ConditionalOnMissingBean
   public RestTemplateCustomizer restTemplateCustomizer(
         final LoadBalancerInterceptor loadBalancerInterceptor) {
      return new RestTemplateCustomizer() {
         @Override
         public void customize(RestTemplate restTemplate) {
            List<ClientHttpRequestInterceptor> list = new ArrayList<>(
                  restTemplate.getInterceptors());
            list.add(loadBalancerInterceptor);
            restTemplate.setInterceptors(list);
         }
      };
   }
}

會給restTemplate設定一個loadBalancerInterceptor,這個LoadBalancerInterceptor如下:

@Bean
public LoadBalancerInterceptor ribbonInterceptor(
      LoadBalancerClient loadBalancerClient,
      LoadBalancerRequestFactory requestFactory) {
   return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}

入參就有一個loadBalancerClient。當RestTemplate發起一個請求,請求就會被LoadBalancerInterceptor攔截:

@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, requestFactory.createRequest(request, body, execution));
}

實際的請求是由loadBalancer發起的。