写点什么

Ribbon 源码分析之 @LoadBalanced 与 LoadBalancerClient

作者:周杰伦本人
  • 2022 年 9 月 02 日
    贵州
  • 本文字数:2643 字

    阅读完需:约 9 分钟

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 实现的负载均衡自动化配置需要满足两个条件


  • @ConditionalOnClass(RestTemplate.class):RestTemplate 必须在当前工程的环境中

  • @ConditionalOnBean(LoadBalancerClient.class):在 Spring 的 Bean 工厂中必须有 LoadBalancerClient 的实现 Bean


自动化配置类中主要做三件事:


  • 创建一个 LoadBalancerInterceptor 的 Bean,用于实现对客户端发起请求时进行拦截,实现客户端负载均衡

  • 创建 RestTemplateCustomizer 的 Bean,用于 RestTemplate 增加 LoadBalancerInterceptor 拦截器

  • 维护被 LoadBalanced 注解修饰的 RestTemplate 对象列表,并在这里进行初始化,通过 RestTemplateCustomizer 的实例给客户端负载均衡的 RestTemplate 增加 LoadBalancerInterceptor 拦截器

总结

这就是 LoadBalancerAutoConfiguration 的源码分析,它可以实现客户端负载均衡器的自动化配置类。这下一篇文章中我们要分析拦截器 LoadBalancerInterceptor 做了什么功能,我们下一篇文章不见不散咯。让我们一起深入 Ribbon 源码,共同学习

发布于: 13 分钟前阅读数: 5
用户头像

还未添加个人签名 2020.02.29 加入

公众号《盼盼小课堂》,多平台优质博主

评论

发布
暂无评论
Ribbon源码分析之@LoadBalanced与LoadBalancerClient_9月月更_周杰伦本人_InfoQ写作社区