首先用过Ribbon的都知道,要想在Spring-Cloud中使用Ribbon,需要在RestTemplate Bean
上加入@LoadBalanced
注解。那么我们可以先看看@LoadBalanced
(代码如下)。
package org.springframework.cloud.client.loadbalancer;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Annotation to mark a RestTemplate or WebClient bean to be configured to use a
* LoadBalancerClient.
* @author Spencer Gibb
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
通过观察可以发现,@LoadBalanced
注解在spring-cloud-commons
工程下org.springframework.cloud.client.loadbalancer
包中,并且@LoadBalanced
的注解上也没有@Import
类型导入Bean的注解。此时猜测是否有可能是某个地方判断了一个类上是有@LoadBalanced
注解,如果有,就做一下处理,这是我们在idea中按ALT+F7
进行查找(如下图)。发现在LoadBalancerWebClientBuilderBeanPostProcessor
类中有相关代码。但是仔细观察,这里是判断某个bean是不是WebClient.Builder
的实现,而且是在reactive
包下,所以猜测是和reactive相关的。那么问题来了,这个@LoadBalanced
注解到底是在哪里被使用了?
此时笔者猜测是不是有LoadBalancedAutoConfiguration
类型的类,结果一查,还真有,而且和@LoadBalanced
在同一个包下(代码如下)。而且LoadBalancedAutoConfiguration
被配置在当前工程的META-INF/spring.factories
中,所以在SpringBoot启动的时候能被加载。
@Configuration(proxyBeanMethods = false)
@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();
@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);
}
}
});
}
@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 {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
/**
* Auto configuration for retry mechanism.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryFactory loadBalancedRetryFactory() {
return new LoadBalancedRetryFactory() {
};
}
}
/**
* Auto configuration for retry intercepting mechanism.
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RetryTemplate.class)
public static class RetryInterceptorAutoConfiguration {
@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);
};
}
}
}
通过观察可以发现,在LoadBalancerAutoConfiguration有着
@LoadBalanced
@Autowired(required = false)
private List<RestTemplate> restTemplates = Collections.emptyList();
这么一个RestTemplate
集合,他被标注了@LoadBalanced
和@Autowired(required = false)
这两个注解,其中依赖注入的地方还不是必须的。这个地方就涉及到了Spring相关的知识了:因为@LoadBalanced
被@Qualifier
注解标注,而@Qualifier
是通过BeanName去依赖注入的,而且必须得找到一个Bean,不然Spring容器在启动的时候会报错,而不是给对象设置为NULL。所以这里的restTemplates
默认给了一个0个元素的集合。当我们自定义了RestTemplate
并加上@Loadbalanced
注解以后,Spring容器会自动帮我们吧定义好的RestTemplate
加入到restTemplates
集合中。
接着我们在当前类中(LoadBalancerAutoConfiguration)发现了下面的代码
@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);
}
}
});
}
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, this.transformers);
}
可以发现在loadBalancedRestTemplateInitializerDeprecated
方法中,它是遍历了所有的restTemplateCustomizers(RestTemplate增强器)
,使用每个增强器对每个RestTemplate
进行处理。那么RestTemplateCustomizer
又是从哪里来,怎么处理的呢?接着在类中往下找,发现如下代码:
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return restTemplate -> {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
};
}
}
可以发现在restTemplateCustomizer
方法中定义了RestTemplateCustomizer
的处理逻辑,就是给每个RestTemplate添加了一个LoadBalancerInterceptor
的拦截器。而LoadBalancerInterceptor
是从上面的ribbonInterceptor
方法中创建的。而新建LoadBalancerInterceptor
的两个参数,LoadBalancerRequestFactory
是从本类的loadBalancerRequestFactory
中创建的。而创建LoadBalancerRequestFactory
和LoadBalancerInterceptor
的LoadBalancerClient
经过查找并没有在本类中。那么按照老规矩,因为LoadBalancerClient
是一个接口,先看看他的实现类,在IDEA中按CART+H
,可以发现它有两个实现类(如下图):
一个非阻塞的、一个阻塞的,那么我们就看一下非阻塞的RibbonLoadBalancerClient
吧。注意它是在spring-cloud-netflix-ribbon
工程下,和上面的@LoadBalanced、LoadBalancerAutoConfiguration
不在同一个工程下哟。然后继续按ALT+F7
查找一下RibbonLoadBalancerClient
是在哪里被创建的。
可以发现RibbonLoadBalancerClient
是被同包下的RibbonAutoConfiguration
类中loadBalancerClient
方法创建的。那么至此为止,Ribbon是如何与SpringCloud整合的就全部看明白了,下一篇继续来学习下LoadBalancerInterceptor
是如何处理的吧~。来个流程图总结下目前的流程吧:
来源:oschina
链接:https://my.oschina.net/u/3367603/blog/4422901