Feign遠程呼叫
Feign是代替RestTemplate進行遠程呼叫的組件,避免了RestTemplate手寫復雜的url容易出錯的問題,并提高代碼的可讀性
使用Feign步驟
1)引入依賴
哪個服務要發送遠程請求就匯入在哪個服務
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2)添加注解
在order-service的啟動類添加注解 @EnableFeignClients 開啟Feign的功能:

3)撰寫Feign的客戶端
在order-service中新建一個介面UserClient,內容如下:①加注解 ②寫url陳述句
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
這個客戶端主要是基于SpringMVC的注解來宣告遠程呼叫的資訊,比如:
- 服務名稱:userservice
- 請求方式:GET
- 請求路徑:/user/
- 請求引數:Long id
- 回傳值型別:User
4)呼叫介面
注入介面類物件,呼叫介面類的方法

自定義配置
Feign可以支持很多的自定義配置,如下表所示:(一般只會修改日志級別來查bug,其他不改)
| 型別 | 作用 | 說明 |
|---|---|---|
| feign.Logger.Level | 修改日志級別 | 包含四種不同的級別:NONE、BASIC、HEADERS、FULL |
| feign.codec.Decoder | 回應結果的決議器 | http遠程呼叫的結果做決議,例如決議json字串為java物件 |
| feign.codec.Encoder | 請求引數編碼 | 將請求引數編碼,便于通過http請求發送 |
| feign. Contract | 支持的注解格式 | 默認是SpringMVC的注解 |
| feign. Retryer | 失敗重試機制 | 請求失敗的重試機制,默認是沒有,不過會使用Ribbon的重試 |
一般情況下,默認值就能滿足我們使用,如果要自定義時,只需要創建自定義的@Bean覆寫默認Bean即可,
下面以日志為例來演示如何自定義配置,
1)組態檔方式
基于組態檔修改feign的日志級別可以針對單個服務:只有通過當前服務中訪問userservice服務時日志會列印
feign:
client:
config:
userservice: # 針對某個微服務的配置
loggerLevel: FULL # 日志級別
也可以針對所有服務:通過當前服務訪問的all服務都會列印日志
feign:
client:
config:
default: # 這里用default就是全域配置,如果是寫服務名稱,則是針對某個微服務的配置
loggerLevel: FULL # 日志級別
而日志的級別分為四種:
不建議FULL,因為會影響性能,一般是BASIC、NONE(默認)
- NONE:不記錄任何日志資訊,這是默認值,
- BASIC:僅記錄請求的方法,URL以及回應狀態碼和執行時間
- HEADERS:在BASIC的基礎上,額外記錄了請求和回應的頭資訊
- FULL:記錄所有請求和回應的明細,包括頭資訊、請求體、元資料,
2)Java代碼方式
也可以基于Java代碼來修改日志級別,先宣告一個類,然后宣告一個Logger.Level的物件:
該類沒有注入到bean所以暫時不起作用,只有當被其他類寫入到注解中才生效
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志級別為BASIC
}
}
如果要全域生效,將其放到啟動類的@EnableFeignClients這個注解中:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
如果是區域生效,則把它放到對應的@FeignClient這個注解中:
@FeignClient(value = "https://www.cnblogs.com/buchizicai/p/userservice", configuration = DefaultFeignConfiguration .class)
Feign優化使用
總結,Feign的優化:
1.日志級別盡量用basic
2.使用HttpClient或OKHttp代替URLConnection
① 引入feign-httpClient依賴
② 組態檔開啟httpClient功能,設定連接池引數
Feign底層發起http請求,依賴于其它的框架,其底層客戶端實作包括:
?URLConnection:默認實作,不支持連接池
?Apache HttpClient :支持連接池
?OKHttp:支持連接池
因此提高Feign的性能主要手段就是使用連接池代替默認的URLConnection,
這里我們用Apache的HttpClient來演示,
1)引入依賴
在order-service的pom檔案中引入Apache的HttpClient依賴:
<!--httpClient的依賴 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
2)配置連接池
在order-service的application.yml中添加配置:
feign:
client:
config:
default: # default全域的配置
loggerLevel: BASIC # 日志級別,BASIC就是基本的請求和回應資訊
httpclient:
enabled: true # 開啟feign對HttpClient的支持
max-connections: 200 # 最大的連接數
max-connections-per-route: 50 # 每個路徑的最大連接數
測驗:
接下來,在FeignClientFactoryBean中的loadBalance方法中打斷點:

Debug方式啟動order-service服務,可以看到這里的client,底層就是Apache HttpClient:

最佳實踐
所謂最近實踐,就是使用程序中總結的經驗,最好的一種使用方式,
自習觀察可以發現,Feign的客戶端與服務提供者的controller代碼非常相似:
feign客戶端:

UserController:

有沒有一種辦法簡化這種重復的代碼撰寫呢?
1、繼承方式【不建議】
一樣的代碼可以通過繼承來共享:
1)定義一個API介面,利用定義方法,并基于SpringMVC注解做宣告,
2)Feign客戶端和Controller都集成改介面

優點:
- 簡單
- 實作了代碼共享
缺點:
-
服務提供方、服務消費方緊耦合
-
引數串列中的注解映射并不會繼承,因此Controller中必須再次宣告方法、引數串列、注解
2、抽取方式
就是將每一個功能業務寫成一個小的微服務,然后其他的大業務可以匯入依賴呼叫這些小的微服務,從而減少重復寫同樣的功能代碼
將Feign的Client抽取為獨立模塊,并且把介面有關的POJO、默認的Feign配置都放到這個模塊中,提供給所有消費者使用,
例如,將UserClient、User、Feign的默認配置都抽取到一個feign-api包中,所有微服務參考該依賴包,即可直接使用,

3、 實作抽取的最佳實踐
1)抽取
首先創建一個module,命名為feign-api:

專案結構:

在feign-api中然后引入feign的starter依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
然后,order-service中撰寫的UserClient、User、DefaultFeignConfiguration都復制到feign-api專案中

2)在order-service中使用feign-api
首先,洗掉order-service中的UserClient、User、DefaultFeignConfiguration等類或介面,
在order-service的pom檔案中中引入feign-api的依賴:
<dependency>
<groupId>cn.itcast.demo</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
修改order-service中的所有與上述三個組件有關的導包部分,改成匯入feign-api中的包
3)重啟測驗
重啟后,發現服務報錯了:

這是因為UserClient現在在cn.itcast.feign.clients包下,而order-service的@EnableFeignClients注解是在cn.itcast.order包下,不在同一個包,無法掃描到UserClient,
4)解決跨服務掃描包問題
在啟動類上添加注解屬性
方式一:
指定Feign應該掃描的包:
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方式二:
指定需要加載的Client介面:這里是陣列可以放多個引數
@EnableFeignClients(clients = {UserClient.class})
本文來自博客園,作者:不吃紫菜,遵循CC 4.0 BY-SA著作權協議,轉載請附上原文出處鏈接:https://www.cnblogs.com/buchizicai/p/17093549.html及本宣告,
本文著作權歸作者所有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/543492.html
標籤:Java
上一篇:Docker安裝使用Kafka
