Ribbon 源码分析之 @LoadBalanced 与 LoadBalancerClient
@LoadBalanced 注解
@LoadBalanced 注解用来给 RestTemplate 做标记,方便使用负载均衡的客户端 LoadBalancerClient 来配置它。
LoadBalancerClient:
public interface LoadBalancerClient {
/**
* Choose a ServiceInstance from the LoadBalancer for the specified service
* @param serviceId the service id to look up the LoadBalancer
* @return a ServiceInstance that matches the serviceId
*/
ServiceInstance choose(String serviceId);
/**
* execute request using a ServiceInstance from the LoadBalancer for the specified
* service
* @param serviceId the service id to look up the LoadBalancer
* @param request allows implementations to execute pre and post actions such as
* incrementing metrics
* @return the result of the LoadBalancerRequest callback on the selected
* ServiceInstance
*/
<T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException;
/**
* Create a proper URI with a real host and port for systems to utilize.
* Some systems use a URI with the logical serivce name as the host,
* such as http://myservice/path/to/service. This will replace the
* service name with the host:port from the ServiceInstance.
* @param instance
* @param original a URI with the host as a logical service name
* @return a reconstructed URI
*/
URI reconstructURI(ServiceInstance instance, URI original);
}
复制代码
接口中,我们通过定义抽象方法来了解客户端负载均衡器中应具备的能力
ServiceInstance choose(String serviceId); 根据传入的服务名 serviceId 从负载均衡器中挑选一个对应服务的实例
T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException; 从负载均衡器中挑选出的服务实例来执行请求内容
URI reconstructURI(ServiceInstance instance, URI original); 为系统构建一个合适的 host:port 形式的 URI
在分布式系统中,我们使用逻辑上的服务名称作为 host 来构建 URI 进行请求。在操作定义中,ServiceInstance 对象带有 host 和 port 具体服务实例,后者 URI 对象使用逻辑服务名定义为 host 的 URI,返回的 URI 内容是通过 ServiceInstance 的服务实例详情拼接出来的 host:port 形式的请求地址。
LoadBalancerClient
LoadBalancerAutoConfiguration 实现客户端负载均衡器的自动化配置类。
LoadBalancerAutoConfiguration:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
/**
* Auto configuration for Ribbon (client side load balancing).
*
* @author Spencer Gibb
* @author Dave Syer
*/
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
public void afterSingletonsInstantiated() {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
}
};
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerInterceptor(loadBalancerClient);
}
}
复制代码
LoadBalancerAutoConfiguration 类头的注解表示 Ribbon 实现的负载均衡自动化配置需要满足两个条件
自动化配置类中主要做三件事:
创建一个 LoadBalancerInterceptor 的 Bean,用于实现对客户端发起请求时进行拦截,实现客户端负载均衡
创建 RestTemplateCustomizer 的 Bean,用于 RestTemplate 增加 LoadBalancerInterceptor 拦截器
维护被 LoadBalanced 注解修饰的 RestTemplate 对象列表,并在这里进行初始化,通过 RestTemplateCustomizer 的实例给客户端负载均衡的 RestTemplate 增加 LoadBalancerInterceptor 拦截器
总结
这就是 LoadBalancerAutoConfiguration 的源码分析,它可以实现客户端负载均衡器的自动化配置类。这下一篇文章中我们要分析拦截器 LoadBalancerInterceptor 做了什么功能,我们下一篇文章不见不散咯。让我们一起深入 Ribbon 源码,共同学习
评论