Spring Cloud Ribbon 源碼分析

一.前言

      咱們在前面兩篇文章分析了Spring Cloud Eureka 註冊中心客戶端的源碼,在註冊中心會有不少同應用名的實例組成集羣供客戶端調用,這時咱們就須要負載策略來實現如何請求服務.這時咱們就會用到Spring Cloud Ribbon,它是一個服務請求方應用內嵌的一個組件,並非一個服務,也就是說Eureka客戶端都集成了Ribbon,在這裏不用額外的導入依賴,用法咱們在Ribbon負載均衡---SpringCloud(三)有過介紹,那麼如今咱們來分析一下源碼,看究竟是怎麼實現的;html

二.Ribbon負載均衡的執行過程

2.1 RestTemplate執行請求

        咱們利用restTemplate執行一個請求,最後都會經過org.springframework.web.client.RestTemplate#doExecute方法,主要內容以下:web

try {
            //利用攔截器建立請求
			ClientHttpRequest request = createRequest(url, method);
			if (requestCallback != null) {
				requestCallback.doWithRequest(request);
			}
            //執行請求,負載的功能在這裏面實現
			response = request.execute();
			handleResponse(url, method, response);
			if (responseExtractor != null) {
				return responseExtractor.extractData(response);
			}
			else {
				return null;
			}
		}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

三.源碼分析

3.1 RestTemplate

        在前面的使用過程當中,咱們知道Ribbon負載均衡主要依賴於RestTemplate實現的,但RestTemplate其實並非Ribbon的組件,咱們看其所在的包可知,該組件在spring-web包下,也就是說RestTemplate只是被Ribbon利用,用於訪問外部服務的一個方法,真正實現負載均衡的是咱們加上其上面的註解@LoadBalanced;spring

3.2 RibbonAutoConfiguration

        若是你讀了以前分析Spring Cloud Eureka源碼分析,相信對***AutoConfiguration很熟悉了吧,延續以前的一向做風,Spring Cloud Ribbon一樣也有一個 RibbonAutoConfiguration,先來分析其實例化條件:app

@Configuration
@ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})
@RibbonClients
@AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")
@AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})
@EnableConfigurationProperties(RibbonEagerLoadProperties.class)
public class RibbonAutoConfiguration {
 ....省略內部代碼...
}

3.2.1 @Configuration

          這個應該不用介紹了吧,不過也說一句,主要使得該類被Spring感知到,與@EnableAutoConfiguration配合使用的,若是入口類沒有@EnableAutoConfiguration,則@Configuration不會生效;負載均衡

3.2.2 @ConditionalOnClass({ IClient.class, RestTemplate.class, AsyncRestTemplate.class, Ribbon.class})

         註解@ConditionalOnClass代表了實例化的條件,當上下文中存在所示的幾個類的時候;這幾個類是幹啥的呢?咱們看一下;異步

3.2.2.1 IClient     

/**
 * A client that can execute a single request. 
 * 
 * @author awang
 *
 */
public interface IClient<S extends ClientRequest, T extends IResponse> {

	/**
	 * Execute the request and return the response. It is expected that there is no retry and all exceptions
     * are thrown directly.
	 */
    public T execute(S request, IClientConfig requestConfig) throws Exception; 
}

       看該類註釋能夠知道,用於訪問服務提供方的一個簡單調用方法, 沒有重試機制,遇到異常則直接拋出,他是一個接口(interface), 也就是說在這裏定義了基礎的執行請求的方法,如有在執行請求有其餘的操做,由其子類實現  工具

由上圖實現接口的子類類名也能夠看出;源碼分析

3.2.2.2 RestTemplate

        RestTemplate相信你們確定或多或少的接觸過,或者使用過相似的工具類;她主要用來創建HTTP鏈接,訪問外部服務的同步模板工具,咱們根據該類的Note也可知,ui

* <p><strong>Note:</strong> by default the RestTemplate relies on standard JDK
 * facilities to establish HTTP connections. You can switch to use a different
 * HTTP library such as Apache HttpComponents, Netty, and OkHttp through the
 * {@link #setRequestFactory} property.

       這裏還介紹了其餘的相似工具包,你們在項目中也能夠應用,看來源碼也不不是隻介紹關於本身的,也能學到相關其餘的東西;url

      RestTemplate提供了六種HTTP方法,Put,Post,Delete,Get,Options,Head,其中區別我就不介紹了,你們能夠點擊或者自由搜索;總之,RestTemplate提供了不少咱們經常使用的模板方法,很靈活,詳細你們打開這個類自由查看吧;

3.2.2.3 AsyncRestTemplate

       與RestTemplate用法相同,與之不一樣的是AsyncRestTemplate用於異步調用,這裏給你們找了個Demo,自由查看;

3.2.2.4 Ribbon

/**
 * A class that can be used to create {@link com.netflix.ribbon.http.HttpResourceGroup}, {@link com.netflix.ribbon.http.HttpResourceGroup.Builder},
 * and dynamic proxy of service interfaces. It delegates to a default {@link com.netflix.ribbon.RibbonResourceFactory} to do the work.
 * For better configurability or in DI enabled application, it is recommended to use {@link com.netflix.ribbon.RibbonResourceFactory} directly.
 *
 */

3.2.3 @RibbonClients

     用於自定義配置,細粒度的;

@Configuration
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(RibbonClientConfigurationRegistrar.class)
public @interface RibbonClients {

	RibbonClient[] value() default {};

	Class<?>[] defaultConfiguration() default {};

}

     咱們知道,負載均衡的策略有輪詢,隨機,權重等等...而Ribbon默認的是輪詢,若是咱們要指定不一樣的策略,就須要在項目入口類使用這個註解導入配置;而一般咱們的服務調用方會調用不少個服務集羣,而調用每一個服務的時候負載策略都不同,所以該註解內部又提供了@RibbonClient註解;

     用法:@RibbonClient用於註解在項目入口類上,name爲服務提供方,value指定自定義負載策略;

             @RibbonClients用於整合多個@RibbonClient註解;defaultConfiguration爲默認的負載策略;

    具體事例咱們以後再提供;//TODO

3.2.4 @AutoConfigureAfter(name = "org.springframework.cloud.netflix.eureka.EurekaClientAutoConfiguration")

     說明該配置類實例化在註解中配置類以後,這也能夠理解,EurekaClientAutoConfiguration是Eureka客戶端的配置,而RibbonAutoConfiguration是客戶端的一個組件的配置,確定先有客戶端,若是須要,纔會有Ribbon的配置;

3.2.5 @AutoConfigureBefore({LoadBalancerAutoConfiguration.class, AsyncLoadBalancerAutoConfiguration.class})

          說明該配置類實例化在註解中配置類以前;註解中類作了什麼,咱們接下來展開;

3.2.5.1 LoadBalancerAutoConfiguration

          負載均衡同步請求自動配置類

3.2.5.2 AsyncLoadBalancerAutoConfiguration

        負載均衡異步請求自動配置類

3.2.6 @EnableConfigurationProperties(RibbonEagerLoadProperties.class)

        用於指定是否支持部分調用服務RibbonClientde 預加載;

        在使用Ribbon的時候,常常會遇到一種狀況就是第一次執行請求超時,這是因爲調用服務的RibbonClient是懶加載的,在第一次請求的時候加載這樣就使得第一次請求的時間會很長,容易超過咱們設定的響應超時時間,從而致使響應超時;經過此項配置能夠避免這種狀況發生;

       在這裏經過@EnableConfigurationProperties開啓了這個配置類經過外部配置文件的屬性配置實例化bean的功能,使得該類能夠經過@ConfigurationProperties註解指定配置屬性在配置文件中的前綴,並將其值注入到成員變量,實例化成bean;

 

 

 

 

 

 

 

 

 

 

 

 

 

 

待續...

相關文章
相關標籤/搜索