(1)首先下載源碼並關聯IDE:@LoadBalanced註解屬於spring-cloud-commons項目,源碼地址: https://github.com/spring-cloud/spring-cloud-commons
我用的源碼是spring-cloud-commons-1.2.3.RELEASE版本
/**
* Annotation to mark a RestTemplate bean to be configured to use a LoadBalancerClient
* 將一個RestTemplate標誌爲底層採用LoadBalancerClient來執行實際的http請求,支持負載均衡
* @author Spencer Gibb
*/
@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Qualifier
public @interface LoadBalanced {
}
(2)很多時候,我們看到這裏就直接懵圈了,基於過往的經驗,嘗試去推測。
這個註解在org.springframework.cloud.client.loadbalancer包中,推測的思路,就是說,我就去看看這個包下面有啥東西。。。。。一般來說,如果是spring cloud或者是spring boot相關的項目,一定會有一個XXAutoConfiguraiton的一個東西
spring-cloud-common,上面的那個包是在這個項目裏面的,找找對應的包
驚人的發現:
AsyncLoadBalancerAutoConfiguration.class
LoadBalancerAutoConfiguration.class
Async。。。。Async一定是下面的那個不帶Async的一個特殊的變種,看類名就知道是支持異步請求負載均衡請求的,看類名和類體系,看看就知道了。。。
Async相關的類體系,可能都是跟異步發起http請求以及負載均衡相關的一些東西,可能是這樣的特殊的機制
但是不帶Async的一套類,可能就是走普通的同步的http請求
肯定默認的就是普通的同步的http請求咯。。。
LoadBalancerAutoConfiguration,看看這個類裏是什麼東西
看看這個註釋,寫的直接就是專門爲ribbon(負載均衡)搞的一個auto configuration類
/**
* Auto configuration for Ribbon (client side load balancing).
* 專門爲ribbon(負載均衡)搞的一個auto configuration類
*
* @author Spencer Gibb
* @author Dave Syer
* @author Will Tran
*/
@Configuration
@ConditionalOnClass(RestTemplate.class)
@ConditionalOnBean(LoadBalancerClient.class)
@EnableConfigurationProperties(LoadBalancerRetryProperties.class)
public class LoadBalancerAutoConfiguration {
@LoadBalanced
@Autowired(required = false)
//new RestTemplate(),實例化了一個bean一定會放入List<RestTemplate>裏面去
private List<RestTemplate> restTemplates = Collections.emptyList();
@Bean
//SmartInitializingSingleton類作用是初始化相關的東西,就是在系統啓動的時候,一定會在某個時機來執行的
public SmartInitializingSingleton loadBalancedRestTemplateInitializer(
final List<RestTemplateCustomizer> customizers) {
return new SmartInitializingSingleton() {
@Override
//afterSingletonsInstantiated方法在SmartInitializingSingleton實例化完了之後來執行的
public void afterSingletonsInstantiated() {
/**
* 拿到當前的RestTemplate list,遍歷。。。對每個RestTemplate,又遍歷一個Cutomizer(專門用來定製化RestTemplate的組件)。
* 用每個Customizer來定製每個RestTemplate
*/
for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {
for (RestTemplateCustomizer customizer : customizers) {
//每個RestTemplate都被Cusotomizer給定製化了
customizer.customize(restTemplate);
}
}
}
};
}
@Autowired(required = false)
private List<LoadBalancerRequestTransformer> transformers = Collections.emptyList();
@Bean
@ConditionalOnMissingBean
public LoadBalancerRequestFactory loadBalancerRequestFactory(
LoadBalancerClient loadBalancerClient) {
return new LoadBalancerRequestFactory(loadBalancerClient, transformers);
}
@Configuration
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
static class LoadBalancerInterceptorConfig {
@Bean
//構造一個用於給RestTemplate定製化的loadBalancerInterceptor攔截器
public LoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient,
LoadBalancerRequestFactory requestFactory) {
return new LoadBalancerInterceptor(loadBalancerClient, requestFactory);
}
@Bean
@ConditionalOnMissingBean
//專門對RestTemplate進行定製化的一個組件
public RestTemplateCustomizer restTemplateCustomizer(
final LoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
//list裏放了一個ClientHttpRequestInterceptor(實現類loadBalancerInterceptor)攔截器
list.add(loadBalancerInterceptor);
//給RestTemplate設置了一個攔截器。。。。。
restTemplate.setInterceptors(list);
}
};
}
}
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryAutoConfiguration {
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate template = new RetryTemplate();
template.setThrowLastExceptionOnExhausted(true);
return template;
}
@Bean
@ConditionalOnMissingBean
public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() {
return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
}
}
@Configuration
@ConditionalOnClass(RetryTemplate.class)
public static class RetryInterceptorAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public RetryLoadBalancerInterceptor ribbonInterceptor(
LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
LoadBalancerRequestFactory requestFactory) {
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
lbRetryPolicyFactory, requestFactory);
}
@Bean
@ConditionalOnMissingBean
public RestTemplateCustomizer restTemplateCustomizer(
final RetryLoadBalancerInterceptor loadBalancerInterceptor) {
return new RestTemplateCustomizer() {
@Override
public void customize(RestTemplate restTemplate) {
List<ClientHttpRequestInterceptor> list = new ArrayList<>(
restTemplate.getInterceptors());
list.add(loadBalancerInterceptor);
restTemplate.setInterceptors(list);
}
};
}
}
}
往後走,有一些Retry相關的代碼,一看就是跟RetryTemplate相關聯的,跟我們用的普通的RestTemplate是區別開來的,Retry相關的代碼,先不用看了,因爲我們沒用過RetryTemplate,那些代碼可能根本就用不着。。。
我們用的就是普通的RestTemplate。。。所以就關注上面的那些代碼就ok了
總結:
1、梳理一下@LoadBalanced註解探索源碼的思路:
(1)@LoadBalanced註解入手,線索直接斷掉
(2)一個經驗技巧,從這個註解所在的項目和包下面入手,來找找相關的東西,有什麼線索
(3)spring boot和spring cloud相關的類,別想多了,直接找XXXAutoConfiguraiton的類,就知道是怎麼回事
(4)找到了這個LoadBalancerAutoConfiguration,在這個類裏面就有了重大的突破
(5)裏面有一個List<RestTemplate>,推測就是我們創建的那個RestTemplate會放到這裏來
(6)用這個RestTemplateCustomizer對每個RestTemplate進行了定製化,給每個RestTemplate設置了interceptor
(7)具體是哪個interceptor呢?LoadBalancerInterceptor,攔截器
2、一張@LoadBalanced註解初探流程圖