【学习记录】Spring Cloud 负载均衡之@LoadBanlanced
RestTemplate之负载均衡
RestTemplate介绍
RestTemplate是一个用于执行 HTTP 请求的同步客户端。它是原始的 Spring REST 客户端,并通过底层 HTTP 客户端库公开了一个简单的模板方法 API。(RestTemplate官网介绍)。下方代码用于注入RestTemplate的Bean。
@Configuration
@LoadBalancerClient(value = "cloud-payment-service", configuration = RestTemplateConfig.class)
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@LoadBanlanced注解
在RestTemplate注入时加上@LoadBanlanced注解,可以使得RestTemplate在请求服务时拥有客户端负载均衡的能力。
@Configuration
@LoadBalancerClient(value = "cloud-payment-service", configuration = RestTemplateConfig.class)
public class RestTemplateConfig {
@Bean
@LoadBalanced
// 开启负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
然而为什么加上@LoadBanlanced注解后,就可以使得RestTemplate在请求服务时拥有客户端负载均衡的能力呢?
我们可以尝试追踪@LoadBanlanced注解的源码,发现该注解的源码没有有效代码,下面是@LoadBanlanced注解的源码:
package org.springframework.cloud.client.loadbalancer;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
接下来我们来看看LoadBalancerAutoConfiguration类:
@Configuration(
proxyBeanMethods = false
)
@Conditional({BlockingRestClassesPresentCondition.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerClientsProperties.class})
public class LoadBalancerAutoConfiguration {
源码过长......
}
LoadBalancerAutoConfiguration类中使用@Autowired和@LoadBanlanced注解自动注入了所有被@LoadBanlanced注解标注的RestTemplate(Bean)。
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired注解不仅可以注入单个Bean,同时也可以注入多个Bean。仔细查看@LoadBalanced注解的源码可以发现,@LoadBanlanced注解被@Qualifier注解修饰,因此我们可以把@LoadBanlanced注解当做一个组合注解,@LoadBanlanced注解在此时拥有了@Qualifier注解的作用。在Spring框架中,当一个类需要注入多个相同类型的bean时,可以使用@Qualifier注解来指定具体的bean实例。具体例子可以阅读这篇文章(@Qualifier注解)。
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = 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);
}
}
});
}
@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 restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
这段自动装配的代码含义不难理解,就是利用了RestTemplate的拦截器,使用RestTemplateCustomizer对所有标注了注解@LoadBalanced的RestTemplate(Bean)添加一个LoadBalancerInterceptor拦截器,而这个拦截器的作用就是对请求的URI进行转换,获取到具体应该请求哪个服务实例ServiceInstance。