Spring Cloud Ribbon 分析(一)之RibbonAutoConfiguration中我们分析了入口配置类的相关介绍,本节介绍LoadBalancerAutoConfiguration这个配置类以及该配置具体作用!
LoadBalancerAutoConfiguration
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties({RibbonEagerLoadProperties.class, ServerIntrospectorProperties.class})
public class RibbonAutoConfiguration {
......
}
LoadBalancerAutoConfiguration在RibbonAutoConfiguration之后被装配
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
......
@Configuration
@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 list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
}
依赖RestTemplate类、LoadBalancerClient实例,然后我们看到里面比较重要的地方private List
@LoadBalanced
/**
* 标记RestTemplate实例,让RestTemplate具备负载作用
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
此处我们注意@Qualifier这个注解,这个注解我们一般用的最多的场景可能是在多个实例Bean都实现了同一个interface接口,我们在使用这些实例的时候,Spring容器会提示我们有多个实例,需要使用者显示给Bean对象赋予具体的名字,然后我们在回头看看这个LoadBalanced注解被标注了这个@Qualifier,那我们可以理解为@LoadBalanced其实是@Qualifier的一个子类,如果还不是很清楚这个原理,我们索性就直接可以理解@LoadBalanced注解其实就是@Qualifier注解,这样就一目了然了
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@LoadBalanced
@Autowired(required = false)
private List restTemplates = Collections.emptyList();
我们这样注册实例时候之后,然后我们的RestTemplate就被扫描到了restTemplates对象中,此时还没有负载的作用
RetryLoadBalancerInterceptor
public class RetryLoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRetryProperties lbProperties;
private LoadBalancerRequestFactory requestFactory;
private LoadBalancedRetryFactory lbRetryFactory;
......
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
......
return template.execute(context -> {
ServiceInstance serviceInstance = null;
if (context instanceof LoadBalancedRetryContext) {
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
serviceInstance = lbContext.getServiceInstance();
}
if (serviceInstance == null) {
//从负载均衡器中获取一个可用的服务(通过RibbonLoadBalancerClient获取可用服务)
serviceInstance = loadBalancer.choose(serviceName);
}
//执行负载均衡器的execute获取结果(通过RibbonLoadBalancerClient获取可用服务)
ClientHttpResponse response = RetryLoadBalancerInterceptor.this.loadBalancer.execute(
serviceName, serviceInstance,
requestFactory.createRequest(request, body, execution));
int statusCode = response.getRawStatusCode();
if (retryPolicy != null && retryPolicy.retryableStatusCode(statusCode)) {
byte[] bodyCopy = StreamUtils.copyToByteArray(response.getBody());
response.close();
throw new ClientHttpResponseStatusCodeException(serviceName, response, bodyCopy);
}
return response;
}, new LoadBalancedRecoveryCallback() {
@Override
protected ClientHttpResponse createResponse(ClientHttpResponse response, URI uri) {
return response;
}
});
}
}
从注释信息我们可以得知拦截类主要做了两件事情,loadBalancer.choose和loadBalancer.execute,此时这个拦截类并没有设置给RestTemplate对象,此时我们在看看下面的片段,我们就比较清晰了
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
先注册了RestTemplateCustomizer实例,Bean实例化完成,包括依赖注入完成,BeadPostProcess,InitializingBean,initMethod等等全部完成后在执行SmartInitializingSingleton
可以理解为Bean的收尾操作,这样就会回调RestTemplateCustomizer的restTemplate.setInterceptors(list),这样就完成了给所有标记了@LoadBalanced注解的RestTemplate对象设置拦截器,就具备了负载的作用
在分析一中提到RibbonLoadBalancerClient,那这个类是怎么用起来的呢?通过什么方式才能被用起来?这样一来,其实总结就是RibbonLoadBalancerClient&RestTemplate结合起来使用,在Spring Cloud Ribbon 分析(三)之RibbonClientConfiguration我们会介绍Ribbon客户端的相关分析!