如果你需要使用 Spring Cloud 客户端负载均衡功能,可以给 RestTemplate bean 加一个 @LoadBalanced 注解,就能让这个 RestTemplate 在请求时拥有客户端负载均衡的能力。@LoadBalanced 注解源码如下:
/** * Annotation to mark a RestTemplate or WebClient bean to be configured to use a * LoadBalancerClient. * 该注释将 RestTemplate 或 WebClient bean 标记为配置为使用 LoadBalancerClient。 * @author Spencer Gibb */ @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @Qualifier public @interface LoadBalanced { }
注意:假如在 Spring 容器中我们注入了两个相同类型的 Bean,使用 @Autowired 注解会抛出(Bean 的实例不唯一)。此时我们就可以使用 @Qualifier 注解通过 Bean 的名称进行精确注入。例如:
@Autowired @Qualifier("userRestTemplate") private RestTemplate<String,User> userRestTemplate; @Autowired @Qualifier("orderRestTemplate") private RestTemplate<String,Order> orderRestTemplate
在 IDEA 的 External Libraries 中,找到 spring-cloud-commons-3.0.1.jar 依赖,打开该依赖找到 META-INF/spring.factories 文件,文件内容如下图:
其中,org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration 是为实现客户端负载均衡器的自动装配类,源码如下:
/** * Auto-configuration for blocking client-side load balancing. * * @author Spencer Gibb * @author Dave Syer * @author Will Tran * @author Gang Li * @author Olga Maciaszek-Sharma */ @Configuration(proxyBeanMethods = false) @ConditionalOnClass(RestTemplate.class) @ConditionalOnBean(LoadBalancerClient.class) @EnableConfigurationProperties(LoadBalancerProperties.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) @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); }; } } private static class RetryMissingOrDisabledCondition extends AnyNestedCondition { RetryMissingOrDisabledCondition() { super(ConfigurationPhase.REGISTER_BEAN); } @ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate") static class RetryTemplateMissing { } @ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", havingValue = "false") static class RetryDisabled { } } /** * 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) @ConditionalOnBean(ReactiveLoadBalancer.Factory.class) @ConditionalOnProperty(value = "spring.cloud.loadbalancer.retry.enabled", matchIfMissing = true) public static class RetryInterceptorAutoConfiguration { @Bean @ConditionalOnMissingBean public RetryLoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerProperties properties, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory, ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) { return new RetryLoadBalancerInterceptor(loadBalancerClient, properties, requestFactory, loadBalancedRetryFactory, loadBalancerFactory); } @Bean @ConditionalOnMissingBean public RestTemplateCustomizer restTemplateCustomizer( final RetryLoadBalancerInterceptor loadBalancerInterceptor) { return 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 loadBalancedRestTemplateInitializerDeprecated( final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) { return () -> restTemplateCustomizers.ifAvailable(customizers -> { 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 restTemplate -> { List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors()); list.add(loadBalancerInterceptor); restTemplate.setInterceptors(list); }; }
会给 restTemplate 设置一个 loadBalancerInterceptor,这个 LoadBalancerInterceptor 如下:
@Bean public LoadBalancerInterceptor loadBalancerInterceptor(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, this.requestFactory.createRequest(request, body, execution)); }
实际的请求是由loadBalancer发起的。