Feign、httpclient、OkHttp3 結合使用


瘋狂創客圈 Java 高並發【 億級流量聊天室實戰】實戰系列 【博客園總入口


瘋狂創客圈 正在進行分布式和高並發基礎原理 的研習,比如下面的一些基礎性的內容:

一、Netty Redis 億級流量 高並發 實戰

二、高並發 springcloud + zookeeper 秒殺

以及有關Springcloud 幾篇核心、重要的文章

一、Springcloud 配置, 史上最全 一文全懂

二、Feign Ribbon Hystrix 三者關系 , 史上最全 深度解析

三、SpringCloud gateway 詳解 , 史上最全

五、常識糾錯:Feign 默認不用 短連接

六、Feign 核心原理,圖解

1 Feign 客戶端實現 類型

前面介紹到了常用的Feign客戶端實現類,大致如下:

(1) Client.Default類:默認的 feign.Client 客戶端實現類,內部使用HttpURLConnnection 完成HTTP URL請求處理;

(2) ApacheHttpClient 類:內部使用 Apache httpclient 開源組件完成HTTP URL請求處理的feign.Client 客戶端實現類;

(3) OkHttpClient類:內部使用 OkHttp3 開源組件完成HTTP URL請求處理的feign.Client 客戶端實現類。

(4) LoadBalancerFeignClient 類:這是一個特殊的 feign.Client 客戶端實現類。內部先使用 Ribbon 負載均衡算法計算server服務器,然后使用包裝的 delegate 客戶端實例,去完成 HTTP URL請求處理。

Feign 在啟動的時候,有兩個與feign.Client 客戶端實例相關的自動配置類,根據多種條件組合,去創建不同類型的 客戶端Spring IOC容器實例。

1.1.1 配置 LoadBalancerFeignClient 負載均衡容器實例

Feign有兩個與Client相關的自動配置類:

(1)org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration

(2)org.springframework.cloud.openfeign.FeignAutoConfiguration

第一個自動配置類,能夠配置具有負載均衡能力的FeignClient容器實例;第二自動配置類,只能配置最原始的FeignClient容器實例。

具備負載均衡能力的 FeignClient 容器實例,所對應的類型為 LoadBalancerFeignClient 類型。前面講到,在SpringCloud中,為了達到高可用,一個微服務至少應該部署兩個以上節點,從這個角度來說,LoadBalancerFeignClient 容器實例,已經成為事實上的標配。

事實上,第一個自動配置類 FeignRibbonClientAutoConfiguration,在容器的裝配次序上,是優先於第二個自動配置類 FeignAutoConfiguration 的。具體可以參見其源碼,節選如下:

import com.netflix.loadbalancer.ILoadBalancer;
//….
@ConditionalOnClass({ILoadBalancer.class, Feign.class})
@Configuration
@AutoConfigureBefore({FeignAutoConfiguration.class})  // 本配置類具備優先權
@EnableConfigurationProperties({FeignHttpClientProperties.class})
@Import({
HttpClientFeignLoadBalancedConfiguration.class,  //配置:包裝ApacheHttpClient實例的負載均衡客戶端
OkHttpFeignLoadBalancedConfiguration.class, //配置:包裝OkHttpClient 實例的負載均衡客戶端
DefaultFeignLoadBalancedConfiguration.class  //配置:包裝Client.Default 實例的負載均衡客戶端
})
public class FeignRibbonClientAutoConfiguration {
    //空的構造器
    public FeignRibbonClientAutoConfiguration() {
    }
//….
}

從源碼中可以看到,FeignRibbonClientAutoConfiguration 的自動配置有兩個前提條件:

(1)當前的類路徑中,存在 ILoadBalancer.class 接口

(2)當前的類路徑中,存在 Feign.class 接口

在這里,重點說一下 ILoadBalancer.class 接口,該接口處於 ribbon 的jar包中。如果需要在類路徑中導入該jar包,則需要在Maven的pom.xml文件中,增加 ribbon 的相關依賴,具體如下:

        <!-- ribbon-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

為了加深大家對客戶端負載均衡的理解,這里將 ILoadBalancer.class 接口的兩個重要的抽象方法列出來,具體如下:

package com.netflix.loadbalancer;
import java.util.List;
public interface ILoadBalancer {
    // 通過負載均衡算法計算server服務器
Server chooseServer(Object var1);
// 取得全部的服務器
List<Server> getAllServers();
//…
}

FeignRibbonClientAutoConfiguration 自動配置類,並沒有直接配置LoadBalancerFeignClient 容器實例,而是使用@Import注解,通過導入其他配置類的方式,完成 LoadBalancerFeignClient 客戶端容器實例的配置。

分別導入了以下三個自動配置類

(1) HttpClientFeignLoadBalancedConfiguration.class

該配置類,負責配置一個包裝 ApacheHttpClient 實例的 LoadBalancerFeignClient負載均衡客戶端。

(2) OkHttpFeignLoadBalancedConfiguration.class

該配置類,負責配置一個包裝 OkHttpClient 實例的 LoadBalancerFeignClient負載均衡客戶端。

(3) DefaultFeignLoadBalancedConfiguration.class

該配置類,負責配置一個包裝 Client.Default 實例的 LoadBalancerFeignClient負載均衡客戶端。

1.1.2 包裝 ApacheHttpClient 實例的負載均衡容器實例

首先來看如何配置一個包裝 ApacheHttpClient 實例的負載均衡容器實例。這個IOC實例的配置,由 HttpClientFeignLoadBalancedConfiguration 自動配置類完成的,其源碼節選如下:

@Configuration
@ConditionalOnClass({ApacheHttpClient.class})
@ConditionalOnProperty(
    value = {"feign.httpclient.enabled"},
    matchIfMissing = true
)
class HttpClientFeignLoadBalancedConfiguration {
    //空的構造器
    HttpClientFeignLoadBalancedConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean({Client.class})
public Client feignClient(
CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient) 
{
        ApacheHttpClient delegate = new ApacheHttpClient(httpClient);
        return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory); // 進行包裝
    }
//…省略不相干的代碼
}

首先,來看源碼中的 feignClient(…)方法,分為兩步:

(1)創建一個 ApacheHttpClient 類型的 feign.Client客戶端實例,該實例的內部使用 Apache httpclient 開源組件完成HTTP URL請求處理;

(2)創建一個 LoadBalancerFeignClient 負載均衡客戶端實例,將 ApacheHttpClient 實例包裝起來,然后返回LoadBalancerFeignClient 客戶端實例,作為 feign.Client 類型的Spring IOC 容器實例。

然后,再看類 HttpClientFeignLoadBalancedConfiguration 上的兩個重要的注解:

(1)@ConditionalOnClass(ApacheHttpClient.class)

(2)@ConditionalOnProperty(value = "feign.httpclient.enabled", matchIfMissing = true)

這兩個條件的含義為

(1)必須滿足 ApacheHttpClient.class 在當前類路徑中存在;

(2)必須滿足工程配置文件中 feign.httpclient.enabled 配置項的值為 true ;

如果以上兩個條件同時滿足,則 HttpClientFeignLoadBalancedConfiguration 自動配置工作就會啟動。

如何驗證呢?
首先在工程配置文件中,將配置項 feign.httpclient.enabled 的值,設置為 false 。然后,在 HttpClientFeignLoadBalancedConfiguration 的 feignClient(…)方法內的某行打上斷點,重新啟動項目,注意觀察會發現,整個啟動過程中,斷點沒有被命中。接下來,將配置項 feign.httpclient.enabled 的值設置為 true,再一次啟動項目,斷點被命中。由此,可以驗證 HttpClientFeignLoadBalancedConfiguration 自動配置類被啟動。

為了滿足 @ConditionalOnClass(ApacheHttpClient.class) 的條件要求,由於ApacheHttpClient類的位置處於feign-httpclient相關的jar包中,所以,需要在pom文件加上 feign-httpclient 以及httpclient 組件相關的 Maven 依賴,具體如下:

     <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-httpclient</artifactId>
            <version>9.5.1</version>
            <!--<version>${feign-httpclient.version}</version>-->
     </dependency>
<dependency>
		<groupId>org.apache.httpcomponents</groupId>
		<artifactId>httpclient</artifactId>
		<version>${httpclient.version}</version>
	</dependency>

對於 feign.httpclient.enabled 配置項設置,根據 @ConditionalOnProperty 注解的屬性matchIfMissing=true 可知,這個可以不用配置,在默認的情況下就為 true。換句話說,如果不做特別的配置,feign.httpclient.enabled 配置項的值,默認為 true。

1.1.3 包裝 OkHttpClient 實例的負載均衡容器實例

接下來,來看如何配置一個包裝 OkHttpClient 實例的負載均衡容器實例。這個IOC實例的配置,由 OkHttpFeignLoadBalancedConfiguration 自動配置類完成的,其源碼節選如下:

@Configuration
@ConditionalOnClass({OkHttpClient.class})
@ConditionalOnProperty("feign.okhttp.enabled")
class OkHttpFeignLoadBalancedConfiguration {
    //空的構造器
    OkHttpFeignLoadBalancedConfiguration () {
    }

    @Bean
    @ConditionalOnMissingBean({Client.class})
public Client feignClient(
CachingSpringLoadBalancerFactory cachingFactory,
SpringClientFactory clientFactory, HttpClient httpClient) 
{
        OkHttpClient delegate = new OkHttpClient (httpClient);
        return new LoadBalancerFeignClient(delegate, cachingFactory, clientFactory); // 進行包裝
    }
//…省略不相干的代碼
}

首先,來看源碼中的 feignClient(…)方法,分為兩步:

(1)創建一個 OkHttpClient 類型的 feign.Client客戶端實例,該實例的內部使用 OkHttp3 開源組件完成HTTP URL請求處理;

(2)創建一個 LoadBalancerFeignClient 負載均衡客戶端實例,將 OkHttpClient實例包裝起來,然后返回LoadBalancerFeignClient 客戶端實例,作為 feign.Client 類型的Spring IOC 容器實例。

然后,再看類 OkHttpFeignLoadBalancedConfiguration 上的兩個重要的注解:

(1)@ConditionalOnClass(OkHttpClient.class)

(2)@ConditionalOnProperty("feign.okhttp.enabled")

這兩個條件的含義為:

(1)必須滿足 OkHttpClient.class 在當前類路徑中存在;

(2)必須滿足工程配置文件中 feign.okhttp.enabled 配置項的值為 true 。

如果以上兩個條件同時滿足,則 OkHttpFeignLoadBalancedConfiguration 自動配置工作就會啟動。

為了滿足 @ConditionalOnClass(OkHttpClient.class) 的條件要求,由於OkHttpClient.class 類的位置處於 feign-okhttp 相關的jar包中,所以,需要在pom文件加上 feign-okhttp 以及 okhttp3 相關的 Maven 依賴。具體如下:


<!-- OkHttp -->
<dependency>
	<groupId>com.squareup.okhttp3</groupId>
	<artifactId>okhttp</artifactId>
</dependency>

<!-- feign-okhttp -->
<dependency>
	<groupId>io.github.openfeign</groupId>
	<artifactId>feign-okhttp</artifactId>
</dependency>

對於 feign.okhttp.enabled 配置項設置,在默認的情況下就為 false。也就是說,如果需要使用feign-okhttp,則一定需要做特別的配置,在工程配置文件中,加上 feign.okhttp.enabled 配置項的值,並且值必須為 true。如果需要使用 feign-okhttp,工程配置文件的配置項大致如下:

feign.httpclient.enabled=false
feign.okhttp.enabled=true

1.1.4 包裝 Client.Default 客戶端實例的負載均衡容器實例

最后,來看如何配置一個包裝默認Client.Default 客戶端實例的負載均衡容器實例。這個IOC實例的配置,由 DefaultFeignLoadBalancedConfiguration 自動配置類所完成的。該配置類,也就是 FeignRibbonClientAutoConfiguration 配置類通過 @import 注解所導入的第3個配置類。

DefaultFeignLoadBalancedConfiguration 的源碼節選如下:

package org.springframework.cloud.openfeign.ribbon;
//…省略import

@Configuration
class DefaultFeignLoadBalancedConfiguration {
    DefaultFeignLoadBalancedConfiguration() {
    }

    @Bean
    @ConditionalOnMissingBean
public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory,
 SpringClientFactory clientFactory)
  {
        return new LoadBalancerFeignClient(
new Default((SSLSocketFactory)null,
 (HostnameVerifier)null), cachingFactory, clientFactory);
    }
}

通過源碼可以看出,如果前面的兩個配置類的條件沒有滿足,feign.Client 的 IOC 容器實例沒有裝配,則:

(1) 創建一個 Client.Default 默認客戶端實例,該實例的內部,使用HttpURLConnnection 完成URL請求處理;

(2) 創建一個 LoadBalancerFeignClient 負載均衡客戶端實例,將 Client.Default 實例包裝起來,然后返回LoadBalancerFeignClient 客戶端實例,作為 feign.Client 類型的Spring IOC 容器實例。

具體,請關注 Java 高並發研習社群博客園 總入口


最后,介紹一下瘋狂創客圈:瘋狂創客圈,一個Java 高並發研習社群博客園 總入口

瘋狂創客圈,傾力推出:面試必備 + 面試必備 + 面試必備 的基礎原理+實戰 書籍 《Netty Zookeeper Redis 高並發實戰

img


瘋狂創客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 億級流量】實戰 開源項目實戰

y Zookeeper Redis 高並發實戰](https://www.cnblogs.com/crazymakercircle/p/11397271.html)》

[外鏈圖片轉存中...(img-Xmc93wKV-1575216360903)]


瘋狂創客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 億級流量】實戰 開源項目實戰


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM