发布时间:2024-01-10 16:00
微服务间的调用,网关请求转发,feign都是通过ribbon实现的,因此学习ribbon的原理还是很重要的,而ribbon的作用是用于负载均衡,springcloud自动化整合配置ribbon是RibbonEurekaAutoConfiguration这个类。对于开发者来说,使用ribbon只需要在RestTemplate上添加@LoadBalanced注解即可实现消费方的负载均衡
resttemplate用于不同服务间的通信和访问,主要有发送GET,POST,PUT,DELETE(*ForEntity方法访问另一个服务的提供的接口返回需要的结果)
开头我们提到在RestTemplate上添加@LoadBalancer注解即可实现负载均衡,通过源码我们可以知道实现的原理。
我们可以找到LoadBalancerClient接口
public interface LoadBalancerClient extends ServiceInstanceChooser {
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
<T> T execute(String serviceId, ServiceInstance serviceInstance, LoadBalancerRequest<T> request) throws IOException;
URI reconstructURI(ServiceInstance instance, URI original);
}
该接口为客户端负载均衡的接口,我们可以找到客户端的自动配置类LoadBalancerAutoConfiguration类
@ConditionalOnClass({RestTemplate.class}) //实现自动化配置 resttemplate类需存在于当前工程中
@ConditionalOnBean({LoadBalancerClient.class}) //实现自动化配置 LoadBalancerClient类的实现bean 需存在于当前工程中
@EnableConfigurationProperties({LoadBalancerRetryProperties.class})
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(
required = false
)
private List<RestTemplate> restTemplates = Collections.emptyList();//创建空的集合存放RestTemplate进行初始化
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> {
restTemplateCustomizers.ifAvailable((customizers) -> {
Iterator var2 = this.restTemplates.iterator();
while(var2.hasNext()) {
RestTemplate restTemplate = (RestTemplate)var2.next();
Iterator var4 = customizers.iterator();
while(var4.hasNext()) {
RestTemplateCustomizer customizer = (RestTemplateCustomizer)var4.next();
customizer.customize(restTemplate); //消费RestTemplate,具体消费方法在下面
}
}
});
};
}
@ConditionalOnClass({RetryTemplate.class}) //假如工程中使用的是RetryTemplate的实现bean则使用该消费方法
public static class RetryInterceptorAutoConfiguration {
public RetryInterceptorAutoConfiguration() {
}
@Bean //注入RetryLoadBalancerInterceptor 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<ClientHttpRequestInterceptor> list = new ArrayList(restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list); //给restTemplate添加拦截器
};
}
}
...
}
可以看出自动化配置类实现的原理是给被@LoadBalancer修饰的resttemplate对象发起请求时,对其进行拦截,负载均衡的是通过拦截器实现的,接下来我们看拦截器的具体实现:
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer, LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer; //构造方法中传入了LoadBalancerClient负载均衡客户端接口
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);
//根据服务名和端口获取到具体的url,调用客户端的execute方法进行拦截实现负载均衡 注意到 this.loadBalancer.execute(执行请求) 和this.requestFactory.createRequest(组装请求)方法
return (ClientHttpResponse)this.loadBalancer.execute(serviceName, this.requestFactory.createRequest(request, body, execution));
}
}