前几篇文章我们分析了Ribbon的简单使用,和执行流程以及配置原理等等,还记得我们集成RestTemplate时使用了@LoadBalanced
注解
// 带负载均衡的http客户端
@LoadBalanced
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
@Autowired
private RestTemplate restTemplate;
@GetMapping("/allOrders/2")
public Object getOrders() {
return restTemplate.getForObject("http://order-service/orders", String.class);
}
我们看看加了@LoadBalanced
注解生成的Bean有哪些不同
我们发现这个注解的作用是给RestTemplate
的Bean增加了一个拦截器LoadBalancerInterceptor
其如何插入拦截器的呢?我们先看看这个注解定义
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Inherited
// 就仅仅是元标注了@Qualifier
@Qualifier
public @interface LoadBalanced {
}
依据我们学习Spring的知识,我们知道这个@Qualifier
注解是用于给Bean分组或tag标记的,这里我们可以大胆猜测一定有一个RestTemplate
自动注入的地方。
package org.springframework.cloud.client.loadbalancer;
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
// 分组标签注入
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
// 创建LoadBalancerRequestFactory Bean
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
// 配置拦截器Bean LoadBalancerInterceptor
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
// 扩展Bean RestTemplateCustomizer
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(restTemplate.getInterceptors());
// 将LoadBalancerInterceptor拦截器Bean追加到RestTemplate中
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
// 新建一个匿名生命周期Bean,初试化后调用afterSingletonsInstantiated,执行插件的插入逻辑
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
restTemplateCustomizers.ifAvailable(new Consumer<List<RestTemplateCustomizer>>() {
@Override
public void accept(List<RestTemplateCustomizer> customizers) {
for (RestTemplate restTemplate : restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
}
});
}
};
}
}
至此,生成的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;
}
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
String serviceName = originalUri.getHost();
// 执行到LoadBalancerClient客户端
return this.loadBalancer.execute(serviceName, requestFactory.createRequest(request, body, execution));
}
}
前面我们已经分析过LoadBalancerClient
,这里我们直接看执行方法
// RibbonLoadBalancerClient
@Override
public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
// 获取负载均衡器,选择合适的服务节点
ILoadBalancer loadBalancer = getLoadBalancer(serviceId);
Server server = getServer(loadBalancer);
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
//
RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server,
serviceId), serverIntrospector(serviceId).getMetadata(server));
// 选择好节点后,最终执行
return execute(serviceId, ribbonServer, request);
}
// 根据选择好的服务节点执行请求逻辑,回到RestTemplate执行
@Override
public <T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException {
Server server = null;
if(serviceInstance instanceof RibbonServer) {
server = ((RibbonServer)serviceInstance).getServer();
}
if (server == null) {
throw new IllegalStateException("No instances available for " + serviceId);
}
RibbonLoadBalancerContext context = this.clientFactory
.getLoadBalancerContext(serviceId);
// 统计信息
RibbonStatsRecorder statsRecorder = new RibbonStatsRecorder(context, server);
try {
// 执行原始请求
T returnVal = request.apply(serviceInstance);
// 统计信息
statsRecorder.recordStats(returnVal);
return returnVal;
} catch (Exception ex) {
statsRecorder.recordStats(ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
总结:
从这里我们可以看出,Ribbon就是通过插件的方式介入了RestTemplate的执行流程,在插件中根据host名称,将名称替换为负载均衡选择出来的服务节点的ip和端口,替换掉原URL中的host发起真正的请求。