feign-底層http請求組件剖析

     這篇文章主要介紹下feign底層使用的http發送請求的組件,下面就一步步得來做剖析。
     我們知道使用feign的時候兩個重要的註解@FeignClient和@EnableFeignClients,這兩個註解分別是標識是一個feign的client,在啓動的時候需要去掃描和register相應的信息,和允許使用feign的client,我們查看源碼可以知道這兩個註解都來自於org.springframework.cloud.netflix.feign,我們可以看到這個包下還有其他很多類,按照spring boot的一貫風格,自動化配置肯定包含auto configuration這樣的單詞,那麼我們可以找到FeignAutoConfiguration這個類,看如下代碼:
// the following configuration is for alternate feign clients if
// ribbon is not on the class path.
// see corresponding configurations in FeignRibbonClientAutoConfiguration
// for load balanced ribbon clients.
@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)
protected static class HttpClientFeignConfiguration {

   @Autowired(required = false)
   private HttpClient httpClient;

   @Bean
   @ConditionalOnMissingBean(Client.class)
   public Client feignClient() {
      if (this.httpClient != null) {
         return new ApacheHttpClient(this.httpClient);
      }
      return new ApacheHttpClient();
   }
}

     這塊代碼其實就是配置底層http發送請求的具體client的,那麼我們看到@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer"),其實含義就是沒有ILoadBalancer這個類纔會執行這個配置,但是由於我們用了Ribbon,這個類是肯定存在的,那麼肯定Feign和Ribbon一起使用的時候自動配置肯定不是這個類,細心看註釋,其實已經告訴了我們配置類是FeignRibbonClientAutoConfiguration,OK,我們轉到這個類去看:
@Bean
@ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
      SpringClientFactory clientFactory) {
   return new LoadBalancerFeignClient(new Client.Default(null, null),
         cachingFactoryclientFactory);
}

@Bean
@ConditionalOnMissingBean
public Request.Options feignRequestOptions() {
   return LoadBalancerFeignClient.DEFAULT_OPTIONS;
}

@Configuration
@ConditionalOnClass(ApacheHttpClient.class)
@ConditionalOnProperty(value "feign.httpclient.enabled"matchIfMissing true)
protected static class HttpClientFeignLoadBalancedConfiguration {

   @Autowired(required false)
   private HttpClient httpClient;

   @Bean
   @ConditionalOnMissingBean(Client.class)
   public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
         SpringClientFactory clientFactory) {
      ApacheHttpClient delegate;
      if (this.httpClient != null) {
         delegate = new ApacheHttpClient(this.httpClient);
      }
      else {
         delegate = new ApacheHttpClient();
      }
      return new LoadBalancerFeignClient(delegatecachingFactoryclientFactory);
   }
}
     這塊代碼有兩個bean是配置Client的,那麼到底是使用哪個呢?第二個static類必須要ApacheHttpClient.class存在,但是我們發現如果項目只包含cloud feign的話這個類是不存在的,所以理論上應該初始化的是代碼最上面的那個Client,那麼我們進Client.Default,不難發現其實用的是HttpURLConnection,這個類繼承於URLConnection,這兩個類都是JDK原生的發送http請求的組件,沒有連接池,但是對每個地址會保持一個長連接,即利用HTTP的persistence connection做請求的優化,我們可以將他替換成HttpClient,從而獲取連接池、超時時間等與性能息息相關的控制能力。其實看第二個bean就可以發現只要引入ApacheHttpClient這個類即可,那麼我們加入io.github.openfeign:feign-httpclient:9.5.0就可以發現有這個類了(這個包也就這一個類),我們debug進去可以發現是真的使用的HttpClient,發現bean容器中沒有HttpClient對象,導致使用的默認是HttpClientBuilder.create().build()創建出來的HttpClient,爲了使我們又足夠的能力來控制這個httpclient,我們需要在bean容器裏面創建一個出來。
     那麼問題來了,我們不可能在每一個消費者中都加入這樣的bean,這樣代碼太重複了,這時我們可以使用spring-boot強大的自動配置,我們來自己自定義一個starter用來創建feign的httpclient,代碼比較簡單,直接見github:https://github.com/JThink/spring-boot-starter-feign-httpclient,主要還是自己創建了帶連接池的httpclient對象。
     其實我們還可以看到auto configuration中還有個OkHttpClient,如果想用這個Client按照同樣的方式即可,對這個組件不熟,就不多做介紹了。

      分享一個項目:https://github.com/JThink/SkyEye對java、scala等運行於jvm的程序進行實時日誌採集、索引和可視化,對系統進行進程級別的監控,對系統內部的操作進行策略性的報警、對分佈式的rpc調用進行trace跟蹤以便於進行性能分析。歡迎對分佈式跟蹤感興趣的交流~~,交流羣:624054633
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章