springcloud ribbon 源碼分析(1)——通過@LoadBalanced註解作爲突破口來找找線索

(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註解初探流程圖

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章