上一節( 跟我學Spring Cloud(Finchley版)-09-Feign )講了Feign的入門姿勢並深入對比了RestTemplate,本節來深入探討Feign的高級特性。總的來說,Feign是一個相對簡單的組件,但細節還是比較多的,一不小心就可能入坑,注意點我會以WARINING的形式標記出來,便於讀者查閱。
Feign配置自定義【細粒度配置】
方式一、代碼配置方式
Spring Cloud Netflix provides the following beans by default for feign (BeanType
beanName: ClassName
):
Decoder
feignDecoder:ResponseEntityDecoder
(which wraps aSpringDecoder
)Encoder
feignEncoder:SpringEncoder
Logger
feignLogger:Slf4jLogger
Contract
feignContract:SpringMvcContract
Feign.Builder
feignBuilder:HystrixFeign.Builder
Client
feignClient: if Ribbon is enabled it is aLoadBalancerFeignClient
, otherwise the default feign client is used.
The OkHttpClient and ApacheHttpClient feign clients can be used by setting feign.okhttp.enabled
orfeign.httpclient.enabled
to true
, respectively, and having them on the classpath.
Spring Cloud Netflix does not provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:
Logger.Level
Retryer
ErrorDecoder
Request.Options
Collection<RequestInterceptor>
SetterFactory
代碼示例:自定義日誌級別
默認Feign是不打印任何日誌的,下面我們來開啓Feign的日誌,Feign有四種日誌級別:
- NONE【性能最佳,適用於生產】:不記錄任何日誌(默認值)。
- BASIC【適用於生產環境追蹤問題】:僅記錄請求方法、URL、響應狀態代碼以及執行時間。
- HEADERS:記錄BASIC級別的基礎上,記錄請求和響應的header。
- FULL【比較適用於開發及測試環境定位問題】:記錄請求和響應的header、body和元數據。
插科打諢 & 惡意揣測
跟我學Spring Cloud(Finchley版)-09-Feign說過,Feign的性能中等,可能官方對自己的性能也是知道的,索性全部關閉日誌了,哈哈
-
將前文的Feign Client修改爲如下:
@FeignClient(name = "microservice-provider-user", configuration = UserFeignConfig.class) public interface UserFeignClient { @GetMapping("/users/{id}") User findById(@PathVariable("id") Long id); } /** * 該Feign Client的配置類,注意: * 1. 該類可以獨立出去; * 2. 該類上也可添加@Configuration聲明是一個配置類; * 配置類上也可添加@Configuration註解,聲明這是一個配置類; * 但此時千萬別將該放置在主應用程序上下文@ComponentScan所掃描的包中, * 否則,該配置將會被所有Feign Client共享,無法實現細粒度配置! * 個人建議:像我一樣,不加@Configuration註解 * * @author zhouli */ class UserFeignConfig { @Bean public Logger.Level logger() { return Logger.Level.FULL; } }
如代碼所示,使用註解
@FeignClient
的configuration
屬性,指定一個類,即可實現Feign配置自定義。TIPS
- 本例簡單起見,直接弄了個外部類作爲配置類
UserFeignConfig
,讀者也可將該類獨立出去作爲一個public class
。
WARNING
- 配置類上也可添加
@Configuraiton
註解,聲明這是一個配置類;但此時千萬別將該放置在主應用程序上下文@ComponentScan
所掃描的包中,否則,該配置將會被所有Feign Client共享(相當於變成了通用配置,其實本質還是Spring父子上下文掃描包重疊導致的問題),無法實現細粒度配置! - 個人建議:像我一樣,不加@Configuration註解,省得進坑。
聯想記憶
還記得Ribbon如何使用Java代碼自定義配置嗎?Ribbon使用Java代碼自定義配置時也必須防止配置類在
@ComponentScan
上下文內,詳見: 跟我學Spring Cloud(Finchley版)-08-Ribbon深入 - 本例簡單起見,直接弄了個外部類作爲配置類
-
在
application.yml
中添加以下內容,將該Feign接口的日誌級別設置爲DEBUG:logging: level: com.itmuch.cloud.study.user.feign.UserFeignClient: debug
-
此時,當該Feign Client的方法被調用時,將會打印類似如下的日誌:
2019-01-10 22:14:10.611 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] ---> GET http://microservice-provider-user/users/1 HTTP/1.1 2019-01-10 22:14:10.611 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] ---> END HTTP (0-byte body) 2019-01-10 22:14:10.623 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] <--- HTTP/1.1 200 (11ms) 2019-01-10 22:14:10.623 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] content-type: application/json;charset=UTF-8 2019-01-10 22:14:10.623 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] date: Thu, 10 Jan 2019 14:14:10 GMT 2019-01-10 22:14:10.623 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] transfer-encoding: chunked 2019-01-10 22:14:10.623 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] 2019-01-10 22:14:10.624 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] {"id":1,"username":"account1","name":"張三","age":20,"balance":100.00} 2019-01-10 22:14:10.624 DEBUG 26321 --- [nio-8010-exec-2] c.i.c.study.user.feign.UserFeignClient : [UserFeignClient#findById] <--- END HTTP (72-byte body)
配套代碼
方法二、屬性配置方式【Edgware開始提供】
從Spring Cloud Edgware開始,Feign支持使用屬性自定義Feign。對於一個指定名稱的Feign Client(例如該Feign Client的名稱爲feignName
),Feign支持如下配置項:
feign:
client:
config:
feignName:
connectTimeout: 5000 # 相當於Request.Options
readTimeout: 5000 # 相當於Request.Options
# 配置Feign的日誌級別,相當於代碼配置方式中的Logger
loggerLevel: full
# Feign的錯誤×××,相當於代碼配置方式中的ErrorDecoder
errorDecoder: com.example.SimpleErrorDecoder
# 配置重試,相當於代碼配置方式中的Retryer
retryer: com.example.SimpleRetryer
# 配置攔截器,相當於代碼配置方式中的RequestInterceptor
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
TIPS
個人並不建議配置retryer,Spring Cloud Camden以及之後的版本中,Spring Cloud關閉了Feign的重試,而是使用Ribbon的重試。如果自己再定義Feign的重試後,那麼可能會造成重試特性的混亂。筆者已在<https://github.com/spring-cloud/spring-cloud-netflix/issues/2330> 提出該問題。
代碼示例:自定義日誌級別
要想用屬性配置方式來達到上面Java代碼方式的效果,只需在application.yml
中添加如下內容即可:
feign:
client:
config:
microservice-provider-user:
loggerLevel: full
logging:
level:
com.itmuch.cloud.study.user.feign.UserFeignClient: debug
配套代碼
Feign配置自定義【通用配置】
上面討論瞭如何配置特定名稱的Feign Client,那麼如果想爲所有的Feign Client都進行配置,該怎麼辦呢?我們知道,@EnableFeignClients
註解上有個defaultConfiguration
屬性,我們可以將默認配置寫成一個類,然後用defaultConfiguration
來引用,例如:
@EnableFeignClients(defaultConfiguration = DefaultRibbonConfig.class)
如果想使用配置屬性的方式,只需使用類似如下的寫法即可。
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
配置優先級
如果你不小心又使用了Java代碼配置Feign,同時又使用了配置屬性配置Feign,那麼使用配置屬性的優先級更高。配置屬性配置的方式將會覆蓋Java代碼配置。如果你想修改代碼配置方式的優先級,可使用如下屬性:feign.client.default-to-properties=false
。
壓縮
一些場景下,我們可能需要對請求或響應進行壓縮,此時可使用以下屬性啓用Feign的壓縮功能。
feign.compression.request.enabled=true
feign.compression.response.enabled=true
對於請求的壓縮,Feign還提供了更爲詳細的設置,例如:
feign.compression.request.enabled=true
feign.compression.request.mime-types=text/xml,application/xml,application/json
feign.compression.request.min-request-size=2048
其中,feign.compression.request.mime-types
用於支持的媒體類型列表,默認是text/xml、application/xml以及application/json。
feign.compression.request.min-request-size
用於設置請求的最小閾值,默認是2048。
繼承
比較重要,業界對繼承特性看法非常不一樣,喜歡的特別喜歡,討厭的特別討厭(例如我)。將以番外形式體現,並對比兩者優缺點,以及最佳實踐,明天或後天更新,敬請期待。
其他特性
Feign其他特性我已經寫了很多了,知識體系已經完備了。懶得再在這個系列裏湊字數,這不是我的風格,直接貼地址吧:
- 生產技巧:Feign如何控制Hystrix的啓停、超時、熔斷?
- 使用Feign實現Form表單提交
- 如何使用Feign構造多參數的請求
- Spring Cloud中,Feign常見問題總結
- Spring Cloud中,如何解決Feign/Ribbon第一次請求失敗的問題?
- 使用Spring Cloud Feign上傳文件
本文首發
http://www.itmuch.com/spring-cloud/finchley-10/