跟我學Spring Cloud(Finchley版)-10-Feign深入

上一節( 跟我學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 a SpringDecoder)
  • Encoder feignEncoder: SpringEncoder
  • Logger feignLogger: Slf4jLogger
  • Contract feignContract: SpringMvcContract
  • Feign.Builder feignBuilder: HystrixFeign.Builder
  • Client feignClient: if Ribbon is enabled it is a LoadBalancerFeignClient, 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;
    }
    }

    如代碼所示,使用註解@FeignClientconfiguration 屬性,指定一個類,即可實現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)

配套代碼

GitHub: https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign-config-java

Gitee: https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign-config-java

方法二、屬性配置方式【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&gt; 提出該問題。

代碼示例:自定義日誌級別

要想用屬性配置方式來達到上面Java代碼方式的效果,只需在application.yml 中添加如下內容即可:

feign:
  client:
    config:
      microservice-provider-user:
        loggerLevel: full
logging:
  level:
    com.itmuch.cloud.study.user.feign.UserFeignClient: debug

配套代碼

GitHub:<https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign-config-properties&gt;

Gitee:<https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign-config-properties&gt;

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其他特性我已經寫了很多了,知識體系已經完備了。懶得再在這個系列裏湊字數,這不是我的風格,直接貼地址吧:

本文首發

http://www.itmuch.com/spring-cloud/finchley-10/

乾貨分享

全是乾貨

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章