- @LoadBalanced
@LoadBalanced注解通常结合RestTemplate使用,RestTemplate是SpringCloud提供的一个编程式的实现远程过程调用的组件,简单来说就是可以实现发送http请求。但是在基于服务发现发送请求时,RestTemplate自己无法实现负载均衡,通常要标注@LoadBalanced。
虽然之后一个RestTemplate对象,但这个对象是线程安全的,多个线程在共同使用这个对象时不会有线程安全问题。
@LoadBalanced@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
- 注解实现原理
@LoadBalanced注解是spring-cloud-starter-loadbalancer依赖引入的,这个依赖引入了LoadBalancerAutoConfiguration。
简单看一下这个类的源码:
@Configuration(proxyBeanMethods = false
)
@Conditional({BlockingRestClassesPresentCondition.class})
@ConditionalOnBean({LoadBalancerClient.class})
@EnableConfigurationProperties({LoadBalancerClientsProperties.class})
public class LoadBalancerAutoConfiguration {@LoadBalanced@Autowired(required = false)private List<RestTemplate> restTemplates = Collections.emptyList();@Autowired(required = false)private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();public LoadBalancerAutoConfiguration() {}@Beanpublic SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {return () -> restTemplateCustomizers.ifAvailable((customizers) -> {for(RestTemplate restTemplate : this.restTemplates) {for(RestTemplateCustomizer customizer : customizers) {customizer.customize(restTemplate);}}});}@Bean@ConditionalOnMissingBeanpublic LoadBalancerRequestFactory loadBalancerRequestFactory(LoadBalancerClient loadBalancerClient) {return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);}@Configuration(proxyBeanMethods = false)@Conditional({RetryMissingOrDisabledCondition.class})static class LoadBalancerInterceptorConfig {LoadBalancerInterceptorConfig() {}@Beanpublic LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory) {return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);}@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {return (restTemplate) -> {List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);restTemplate.setInterceptors(list);};}@Bean@ConditionalOnBean({LoadBalancerInterceptor.class})@ConditionalOnMissingBeanLoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor(final LoadBalancerInterceptor loadBalancerInterceptor, ApplicationContext context) {return new LoadBalancerRestClientBuilderBeanPostProcessor(loadBalancerInterceptor, context);}}private static class RetryMissingOrDisabledCondition extends AnyNestedCondition {RetryMissingOrDisabledCondition() {super(ConfigurationPhase.REGISTER_BEAN);}@ConditionalOnMissingClass({"org.springframework.retry.support.RetryTemplate"})static class RetryTemplateMissing {RetryTemplateMissing() {}}@ConditionalOnProperty(value = {"spring.cloud.loadbalancer.retry.enabled"},havingValue = "false")static class RetryDisabled {RetryDisabled() {}}}@Configuration(proxyBeanMethods = false)@ConditionalOnClass({RetryTemplate.class})public static class RetryAutoConfiguration {public RetryAutoConfiguration() {}@Bean@ConditionalOnMissingBeanpublic LoadBalancedRetryFactory loadBalancedRetryFactory() {return new LoadBalancedRetryFactory() {};}}@Configuration(proxyBeanMethods = false)@ConditionalOnClass({RetryTemplate.class})@ConditionalOnBean({ReactiveLoadBalancer.Factory.class})@ConditionalOnProperty(value = {"spring.cloud.loadbalancer.retry.enabled"},matchIfMissing = true)public static class RetryInterceptorAutoConfiguration {public RetryInterceptorAutoConfiguration() {}@Bean@ConditionalOnMissingBeanpublic RetryLoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalancerClient, LoadBalancerRequestFactory requestFactory, LoadBalancedRetryFactory loadBalancedRetryFactory, ReactiveLoadBalancer.Factory<ServiceInstance> loadBalancerFactory) {return new RetryLoadBalancerInterceptor(loadBalancerClient, requestFactory, loadBalancedRetryFactory, loadBalancerFactory);}@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(final RetryLoadBalancerInterceptor loadBalancerInterceptor) {return (restTemplate) -> {List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);restTemplate.setInterceptors(list);};}@Bean@ConditionalOnBean({RetryLoadBalancerInterceptor.class})@ConditionalOnMissingBeanLoadBalancerRestClientBuilderBeanPostProcessor lbRestClientPostProcessor(final RetryLoadBalancerInterceptor loadBalancerInterceptor, ApplicationContext context) {return new LoadBalancerRestClientBuilderBeanPostProcessor(loadBalancerInterceptor, context);}}
}
核心实现原理:
- 从容器中拿到所有标注了@LoadBalanced注解的Bean,所以没有标注 @LoadBalanced注解的RestTemplate是无法实现负载均衡的。
@LoadBalanced@Autowired(required = false)private List<RestTemplate> restTemplates = Collections.emptyList();
- 拿到这些Bean对象之后,给这些Bean对象设置请求拦截器
@Beanpublic SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {return () -> restTemplateCustomizers.ifAvailable((customizers) -> {for(RestTemplate restTemplate : this.restTemplates) {for(RestTemplateCustomizer customizer : customizers) {customizer.customize(restTemplate);}}});}
这里就是调用了customizer.customize(restTemplate) 来为每一个RestTemplate添加拦截器。
RestTemplateCustomizer 是一个函数式接口,同样在LoadBalancerAutoConfiguration进行了实现
public interface RestTemplateCustomizer {void customize(RestTemplate restTemplate);
}
@Bean@ConditionalOnMissingBeanpublic RestTemplateCustomizer restTemplateCustomizer(final LoadBalancerInterceptor loadBalancerInterceptor) {return (restTemplate) -> {List<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());list.add(loadBalancerInterceptor);restTemplate.setInterceptors(list);};}
很明显这里就是使用lambda表达式定义了一个RestTemplateCustomizer 的实现。而这个方法就是容器中获取LoadBalancerInterceptor,然后获取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) {this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));}public ClientHttpResponse intercept(final HttpRequest request, final byte[] body, final ClientHttpRequestExecution execution) throws IOException {URI originalUri = request.getURI();String serviceName = originalUri.getHost();Assert.state(serviceName != null, "Request URI does not contain a valid hostname: " + originalUri);return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));}
}
很明显可以看到intercept中使用了LoadBalancerClient进行了服务负载均衡。
简而言之就是LoadBalancerAutoConfiguration这个类获取到了容器中所有的RestTemplate组件,并添加了负载均衡拦截器,这样@Bean的RestTemplate自动就有了负载均衡能力。