1. 程式人生 > >Feign的覆寫預設配置和Feign的日誌

Feign的覆寫預設配置和Feign的日誌

  • Feign的覆寫預設配置
    A central concept in Spring Cloud’s Feign support is that of the named client. Each feign client is part of an ensemble of components that work together to contact a remote server on demand, and the ensemble has a name that you give it as an application developer using the @FeignClient annotation. Spring Cloud creates a new ensemble as anApplicationContext on demand for each named client using FeignClientsConfiguration. This contains (amongst other things) an feign.Decoder, a feign.Encoder, and a feign.Contract.

上面是官網的API文件中的說明,如下是我的翻譯:
Spring Cloud的Feign支援的一箇中心概念是命名客戶端。每個feign client是整體的一部分,它們一起工作以按需聯絡遠端伺服器,並且該整體具有一個名稱,開發人員可以使用@FeignClient將其命名。Spring Cloud根據需要使用FeignClientsConfiguration為每個命名的客戶端建立一個新的整體作為ApplicationContext。這包含(其他)feign.Decoder,feign.Encoder和feign.Contract。

Spring Cloud lets you take full control of the feign client by declaring additional configuration (on top of theFeignClientsConfiguration) using @FeignClient. Example:

@FeignClient(name = “stores”, configuration = FooConfiguration.class)
public interface StoreClient {
//..
}

上面文件說,通過使用額外的配置@FeignClient註解,可以使Spring Cloud讓你完全的控制feign客戶端。並且官網還給出了例子,那麼我們也按照它提供的例子來在我們的工程師運用起來。
將介面類UserFeignClient進行修改,如下修改後的程式碼:

@FeignClient(name = "microservice-provider-user"
, configuration = FooConfiguration.class) public interface UserFeignClient { /** * 注意:要使用Feign的註解 * <p> * <code>@RequestLine("GET /repos/{owner}/{repo}/contributors")</code> * <br> * <code>List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);</code> * * @param id * @return */ @RequestMapping(method = RequestMethod.GET, value = "/simple/{id}") // @RequestLine("GET /simple/{id}") public User findById(@PathVariable("id") Long id); }

在配置FeignClient的configuration指定的值FooConfiguration,這個類是不存在的,這裡我們需要新建,官網中也給我建立了這個類的程式碼,下面是我根據官網的程式碼和我實際需求修改後的:

@Configuration
public class FooConfiguration {
    @Bean
    public Contract feignContract() {
        return new feign.Contract.Default();
    }
}

完成之後,可以開始啟動工程了,當我們在啟動時,會報錯,錯誤關鍵如下:
Caused by: java.lang.IllegalStateException: Method findById not annotated with HTTP method type (ex. GET, POST)
這裡錯誤是說我們沒有使用Http方法的註解導致的,但我們仔細檢查下程式碼,我們使用的是@RequestMapping的註解方式,這裡我也不知道怎麼解釋,可能是我沒有深刻的理解吧,看了Feign 的GitHub的相關程式碼後,我發現了另一種註解方式:

interface GitHub {
  @RequestLine("GET /repos/{owner}/{repo}/contributors")
  List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}

好的,現在將@RequestMapping註解改成@RequestLine,以及引數也修改成@Param,修改後:

@FeignClient(name = "microservice-provider-user", configuration = FooConfiguration.class)
public interface UserFeignClient {

    /**
     * 注意:要使用Feign的註解
     * <p>
     * <code>@RequestLine("GET /repos/{owner}/{repo}/contributors")</code>
     * <br>
     * <code>List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);</code>
     * 
     * @param id
     * @return
     */
    @RequestLine("GET /simple/{id}")
    public User findById(@Param("id") Long id);

}

修改完成之後,再次重啟服務,發現啟動成功,而且可以訪問介面了。

WARNING Previously, using the url attribute, did not require the name attribute. Using name is now required.

官網中有個這樣的提醒:以前在使用URL屬性時,不必要使用那麼屬性,但是在現在Feign中name屬性就是必要的了。
它也給了例子,如下面程式碼:

@FeignClient(name = "${feign.name}", url = "${feign.url}")
public interface StoreClient {
    //..
}

現在我們也來在我們的工程中實際運用一下。
新建一個介面FeignClient2,程式碼如下:

@FeignClient(name = "xxx", url = "http://localhost:8761/", configuration = BeanConfiguration.class)
public interface FeignClient2 {

//  @RequestMapping(value = "/eureka/apps/{serviceName}")
    @RequestLine("GET /eureka/apps/{serviceName}")
    public String findServiceInfoEurekaByServieName(@Param("serviceName") String serviceName);

}

我們通過這個feign來獲取eureka server下注冊的例項資訊,通過@FeignClient註解配置了name、url和configuration屬性,這裡那麼我隨便寫的內容,因為這個僅僅表示這個feign的名稱而已,url配置的是eureka server的地址,configuration我們這裡配的一個需要新建的類BeanConfiguration。
大家肯定還有疑惑,這個BeanConfiguration類配置了是起什麼作用的了?
好的,這裡就為大家答疑解惑,首先貼出該類的程式碼:

@Configuration
public class BeanConfiguration {

    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor("micheal", "123456");
    }
}

看到程式碼,也許大家可能就明白了,這個在請求時不需要輸入使用者名稱和密碼就可以直接呼叫Eureka Server,因為Feign通過這個配置的configuration類為我們做了使用者名稱和密碼的許可權認證了。
完成上面的內容了,接下來就是見證奇蹟的時刻了。
啟動服務,在Eureka Server中檢視到註冊成功了,我們就可以通過瀏覽器進行查看了。

  • Feign Logging 日誌

A logger is created for each Feign client created. By default the name of the logger is the full class name of the interface used to create the Feign client. Feign logging only responds to the DEBUG level.

application.yml
logging.level.project.user.UserClient: DEBUG

官網API說:為每個Feign 客戶端建立日誌,日誌的預設名稱為所建立的Feign客戶端介面類的整個類名。Feign的日誌僅僅只有在DEBUG級別時才會響應。
官網給我們提供了例子,按照官網提供的做法,現在來為我們對的工程配置Feign Logging。
以我們microservice-consumer-movie-feign-customizing工程為例,在配置檔案application.yml進行Feign 日誌配置,如下配置:

logging:
  level:
    com.spring.cloud.feign.UserFeignClient: DEBUG

com.spring.cloud.feign.UserFeignClient 是Feign Client介面類的完成類名。好了,完成了這個配置,是不是有點超激動想要一看是否真的能打印出日誌了。
先不著急,我們接著檢視官網API文件中的內容:

The Logger.Level object that you may configure per client, tells Feign how much to log. Choices are:
• NONE, No logging (DEFAULT).
• BASIC, Log only the request method and URL and the response status code and execution time.
• HEADERS, Log the basic information along with request and response headers.
• FULL, Log the headers, body, and metadata for both requests and responses.
For example, the following would set the Logger.Level to FULL:

@Configuration
public class FooConfiguration {
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

官網給我們提供了一些日誌級別的等級,這裡就不一一翻譯了。我們的重點是在上面所給的例子,上面例子說為日誌設定為FULL級別的日誌。
好,開始我們的配置,找到我們所配Feign 日誌的客戶端介面類,我們發現我們配值得configuration的類時FooConfiguration類,好我們將官網中的feignLoggerLevel方法新增到我們的FooConfiguration類中。
完成之後,我們啟動工程,並先將日誌清掉,再重新請求介面,發現確實打印出日誌來了。
這裡還需要補充一下,在配置檔案application.yml中配置了Feign客戶端日誌之後,如果不在configuration類中新增日誌級別的話,是不會打印出日誌的。因為在官網API中有提到“NONE, no loggin(DEFAULT)”,就是說預設日誌級別時NONE的。