SpringCloud之Ribbon客户端负载应用及原理分析
SpringCloud之Ribbon客户端负载原理分析(一)-LoadBalancerInterceptor原理分析
SpringCloud之Ribbon客户端负载原理分析(二)-RibbonLoadBalancerClient原理分析
SpringCloud之Ribbon客户端负载原理分析(三)-ILoadBalancer原理分析
本文主要内容:
从@LoadBalanced作为切入点,了解LoadBalancerInterceptorr的添加过程及作用
- 前期准备知识:了解restemplate的基本使用和@Qualifier注解特性
- LoadBalancerInterceptor原理分析
- 了解LoadBalancerInterceptor的初始化过程
- 了解LoadBalancerInterceptor如何拦截请求处理
一、前期准备知识
在学习@LoadBalanced的原理之前,有两个知识点需要了解:
restemplate基本使用
@Qualifier注解的使用和特性
这两个知识点都比较简单,详细介绍可以自行学习,本文不做过多说明,只会说一下其中的关键点
1.1、restemplate基本使用
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
简单说,就是通过RestTemplate进行服务间的调用
String result = restTemplate.getForObject("http://spring-cloud-order-service/orders", String.class);
1.2、了解@Qualifier注解的特性
@Qualifier注解的特性,有两点需要特别关注:
当指定@Qualifier注解的 value() 属性时
:@Qualfier注解进行过滤的同时,还会按照 Bean 名称(Name)或者别名(Alias)等于value进行Bean筛选当不指定@Qualifier注解的 value() 属性时
:会按照@Qualfier元注解过滤,即:只要添加了@Qualfier注解就会被扫描到
我们以下面代码为例进行理解:
- TestController的restemplates1:因为指定@Qualifier(“restemplateA”),所以只会注入restemplateA
- TestController的restemplates2:因为@Qualifier()未指定value值,所以会注入所有增加了@Qualifier注解的RestTemplate,即:会注入restemplateA、restemplateB
如果RestemplateConfiguration中的RestTemplate都不增加 @Qualifier注解,TestController在注入RestTemplate时会报错
@Configuration
public class RestemplateConfiguration {
@Qualifier
@Bean("restemplateA")
RestTemplate testClass1(){
return new RestTemplate();
}
@Qualifier
@Bean("restemplateB")
RestTemplate testClass2(){
return new RestTemplate();
}
}
@RestController
public class TestController {
// 只会注入名字为restemplateA的RestTemplate
@Qualifier("restemplateA")
@Autowired
List<RestTemplate> restemplatesList1= Collections.emptyList();
@Qualifier
@Autowired
List<RestTemplate> restemplatesList2= Collections.emptyList();
@GetMapping("/test")
public void test(){
System.out.println("restemplatesList1-->"+restemplatesList1);
System.out.println("restemplatesList2-->"+restemplatesList2);
}
}
我们查看@LoadBalanced注解的源码,可以发现它就添加了@Qualifier注解,所以@LoadBalanced注解具有上面@Qualifier注解的两个的特性
:
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {}
二、LoadBalancerInterceptor原理分析
做好前面的基础准备以后,我们开始进行Ribbbon原理分析。
首先,我们是通过@LoadBalanced注解开启客户端负载功能的,而@LoadBalanced注解的作用就是给restemplate添加一个LoadBalancerInterceptor,接下来我们就从LoadBalancerInterceptor初始化过程开始进行原理分析。
2.1、LoadBalancerInterceptor初始化过程
2.1.1、LoadBalancerInterceptor初始化过程示意图
下面是LoadBalancerInterceptor初始化过程时,方法调用的示意图,可以配合源码分析观看:
下面通过源码具体分析Spring Cloud Ribbon的初始化过程
2.1.2、LoadBalancerAutoConfiguration源码分析
基于Springboot的自动装配,Spring会自动加载LoadBalancerAutoConfiguration,而LoadBalancerAutoConfiguration会完成以下操作:
- 获取所有增加了@LoadBalanced注解的RestTemplate
- 初始化一个LoadBalancerInterceptor拦截器:ribbonInterceptor
- 初始化一个RestTemplateCustomizer:它的作用是为RestTemplate添加LoadBalancerInterceptor拦截器
- 调用(3)中RestTemplateCustomizer的方法,为(1)中的每个RestTemplate,添加一个(2)生成的LoadBalancerInterceptor拦截器
LoadBalancerAutoConfiguration源码如下,可以查看方法注解了解核心方法的作用:
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
/**
* 注入所有增加了@LoadBalanced注解的RestTemplate(基于@Qualifier注解特性)
*/
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
/**
* 1、获取所有的RestTemplateCustomizer
* 2、调用RestTemplateCustomizer中的方法,为restTemplatetians中的每一个RestTemplate添加拦截器
* 其中一个RestTemplateCustomizer:就是为restTemplate添加LoadBalancerInterceptor拦截器
*/
@Bean
public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
return () -> restTemplateCustomizers.ifAvailable(customizers -> {
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
customizer.customize(restTemplate);
}
}
});
}
/**
* 初始化一个LoadBalancerRequestFactory,其中的参数LoadBalancerClient由自动注入
*/
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
/**
* 初始化一个LoadBalancerInterceptor,构造两个参数:
* 1、loadBalancerClient
* 2、LoadBalancerRequestFactory
*/
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
/**
* 初始化一个RestTemplateCustomizerr,传入的构造参数是上面初始化的的LoadBalancerInterceptor
* RestTemplateCustomizer的作用:为restTemplate添加LoadBalancerInterceptor拦截器
*/
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
// 其他代码省略
}
上面的源码注解中写到:
在初始化ribbonInterceptor时,会自动注入一个LoadBalancerClient,而这个LoadBalancerClient是在RibbonAutoConfiguration中完成初始化的
2.2.3、RibbonAutoConfiguration源码分析
RibbonAutoConfiguration的源码分析:
@AutoConfigureBefore的作用
:定义要求RibbonAutoConfiguration需要在LoadBalancerAutoConfiguration之前被加载loadBalancerClient()方法
:生成一个LoadBalancerClient客户端,即:RibbonLoadBalancerClient
RibbonAutoConfiguration.class源码:
@Configuration
@Conditional(RibbonAutoConfiguration.RibbonClassesConditions.class)
@RibbonClients
@AutoConfigureAfter(
name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({ LoadBalancerAutoConfiguration.class,
AsyncLoadBalancerAutoConfiguration.class })
@EnableConfigurationProperties({ RibbonEagerLoadProperties.class,
ServerIntrospectorProperties.class })
public class RibbonAutoConfiguration {
@Autowired(required = false)
private List<RibbonClientSpecification> configurations = new ArrayList<>();
@Autowired
private RibbonEagerLoadProperties ribbonEagerLoadProperties;
@Bean
public HasFeatures ribbonFeature() {
return HasFeatures.namedFeature("Ribbon", Ribbon.class);
}
@Bean
@ConditionalOnMissingBean
public SpringClientFactory springClientFactory() {
SpringClientFactory factory = new SpringClientFactory();
factory.setConfigurations(this.configurations);
return factory;
}
// 初始化一个LoadBalancerClient,即:RibbonLoadBalancerClient
@Bean
@ConditionalOnMissingBean(LoadBalancerClient.class)
public LoadBalancerClient loadBalancerClient() {
return new RibbonLoadBalancerClient(springClientFactory());
}
@Bean
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryPolicyFactory(
final SpringClientFactory clientFactory) {
return new RibbonLoadBalancedRetryFactory(clientFactory);
}
@Bean
@ConditionalOnMissingBean
public PropertiesFactory propertiesFactory() {
return new PropertiesFactory();
}
@Bean
@ConditionalOnProperty("ribbon.eager-load.enabled")
public RibbonApplicationContextInitializer ribbonApplicationContextInitializer() {
return new RibbonApplicationContextInitializer(springClientFactory(),
ribbonEagerLoadProperties.getClients());
}
// 代码省略
}
LoadBalancerClient最终会处理restemplate的请求数据,而LoadBalancerClient具有以下作用:
- 存储并维护服务列表,
- 根据路由规则,通过servicename获取一个服务地址
- 将请求数据发送到服务地址
2.2、LoadBalancerInterceptor拦截请求处理
2.2.1、LoadBalancerInterceptor的拦截过程示意图
2.2.2、LoadBalancerInterceptor源码分析
通过上面的自动装配会为每一个添加了@LoadBalancer的resttemplate添加一个LoadBalancerInterceptor拦截器(ribbonInterceptor),而这个LoadBalancerInterceptor.intercept()会拦截restemplate的所有请求,并进行以下处理:
- 通过构造方法传入一个LoadBalancerClient
- 拦截restemplate请求数据,解析url中的serviceName
- 将请求数据封装成LoadBalancerRequest
- 将serviceName和LoadBalancerRequest交由LoadBalancerClient进行处理
public class LoadBalancerInterceptor implements ClientHttpRequestInterceptor {
// 通过构造方法传入的LoadBalancerClient
private LoadBalancerClient loadBalancer;
private LoadBalancerRequestFactory requestFactory;
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer,
LoadBalancerRequestFactory requestFactory) {
this.loadBalancer = loadBalancer;
this.requestFactory = requestFactory;
}
/**
* LoadBalancerInterceptor构造方法
*/
public LoadBalancerInterceptor(LoadBalancerClient loadBalancer) {
// for backwards compatibility
this(loadBalancer, new LoadBalancerRequestFactory(loadBalancer));
}
/**
* 拦截restemplate的所有请求,进行处理
*/
@Override
public ClientHttpResponse intercept(final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) throws IOException {
// 1、获取请求url
final URI originalUri = request.getURI();
// 2、解析serviceName
String serviceName = originalUri.getHost();
Assert.state(serviceName != null,
"Request URI does not contain a valid hostname: " + originalUri);
// 3、将请求数据封装成LoadBalancerRequest<T>
// 4、将serviceName和LoadBalancerRequest交由LoadBalancerClient进行处理
return this.loadBalancer.execute(serviceName,
this.requestFactory.createRequest(request, body, execution));
}
}
这里是通过调用LoadBalancerRequestFactory.createRequest()方法创建LoadBalancerRequest
2.2.3、LoadBalancerRequestFactory源码分析
LoadBalancerRequestFactory.createRequest()方法:
- 通过匿名内部类的方法,创建一个LoadBalancerRequest
- 通过Lambda表达式实现了LoadBalancerRequest.apply()方法
public class LoadBalancerRequestFactory {
private LoadBalancerClient loadBalancer;
private List<LoadBalancerRequestTransformer> transformers;
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer,
List<LoadBalancerRequestTransformer> transformers) {
this.loadBalancer = loadBalancer;
this.transformers = transformers;
}
public LoadBalancerRequestFactory(LoadBalancerClient loadBalancer) {
this.loadBalancer = loadBalancer;
}
/*
* 通过匿名内部类的方法,创建一个LoadBalancerRequest
* 通过Lambda表达式实现了LoadBalancerRequest.apply()方法
*/
public LoadBalancerRequest<ClientHttpResponse> createRequest(
final HttpRequest request, final byte[] body,
final ClientHttpRequestExecution execution) {
return instance -> {
HttpRequest serviceRequest = new ServiceRequestWrapper(request, instance,
this.loadBalancer);
if (this.transformers != null) {
for (LoadBalancerRequestTransformer transformer : this.transformers) {
serviceRequest = transformer.transformRequest(serviceRequest,
instance);
}
}
return execution.execute(serviceRequest, body);
};
}
}
2.2.4、LoadBalancerInterceptor的总结
LoadBalancerInterceptor拦截Restemplate的所有请求,从中解析出serviceName,并创建一个LoadBalancerRequest交给RibbonLoadBalancerClient处理
下篇文章开始分析:RibbonLoadBalancerClient