開篇
Feign 是聲明式、模板化的 HTTP 客戶端, 可以幫助我們更快捷、優雅地調用 HTTP API;Spring Cloud 為 Feign 添加了 Spring MVC 的注解支持,并整合了 Ribbon 和 Eureka 來為使用 Feign 時提供負載均衡;在 Spring Cloud 中使用 Feign 是非常容易的。
本篇主要介紹 SpringBoot 中要玩轉 Feign 需要掌握的如添加 pom 依賴、客戶端注解啟用、切換底層 HttpClient、配置數據壓縮、調整日志級別、定制配置、配置的優先級機制、增加攔截器以及攔截器的追加機制等知識。
一、使用 Feign 的示例
1.1 添加依賴
<dependencies>
<!--openfein的依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
</dependencies>
復制代碼
1.2 啟用 Feign
在 SpringBoot 的啟用類上添加注解@EnableFeignClients,@EnableFeignClients用于開啟 Feign,會自動掃描@FeignClient標注的 FeignClient 接口。
@SpringBootApplication
@EnableFeignClients
@EnableWeb
public class FeignApplication {
public static void main(String[] args) {
SpringApplication.run(FeignApplication.class,args);
}
}
復制代碼
1.3 編寫 FeignClient 接口
@FeignClient(
name = "demo-service",
url = "http://localhost:8080/feign/server/",
configuration = FeignInterceptor.class,
fallback = TestService.DefaultFallback.class
)
public interface TestService {
@RequestMapping(value = "/getError/{id}", method = RequestMethod.GET)
public String getError(@RequestParam("id") Integer id);
@RequestMapping(value = "/get1", method = RequestMethod.GET)
public String get1();
@RequestMapping(value = "/get2/{param}", method = RequestMethod.GET)
public String get2(@RequestParam("param") String param);
@RequestMapping(value = "/post1", method = RequestMethod.POST)
public FeignDemo post1(@RequestBody FeignDemo demo);
復制代碼
1.4 編寫對應的服務端
@RestController
@RequestMapping("/feign/server")
public class FeignServerController {
@GetMapping("/get1")
public String get1() {
return "get1";
}
@GetMapping("/get2/{para}")
public String get2(@PathVariable("para") String para){
return para;
}
@PostMapping("/post1")
public FeignDemo post1(@RequestBody FeignDemo demo) {
return demo;
}
}
復制代碼
public class FeignDemo {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "FeignDemo{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
復制代碼
1.5 調用 FeignClient
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {FeignApplication.class},webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
@ActiveProfiles("dev,feign")
public class FeignClientTest {
@Autowired
private TestService testService;
@Test
public void testFallback(){
testService.getError(1);
}
@Test
public void testGet1(){
System.out.println(testService.get1());
System.out.println(testService.get2("abc"));
System.out.printf("..");
FeignDemo feignDemo = new FeignDemo();
feignDemo.setName("name");
feignDemo.setAge(1);
System.out.println(testService.post1(feignDemo));
}
@Component
public class DefaultFallback implements TestService {
@Override
public String getError(@RequestParam("id") Integer id){
return "";
}
@Override
public String get1() {
return null;
}
@Override
public String get2(String param) {
return null;
}
@Override
public FeignDemo post1(FeignDemo demo) {
return null;
}
}
}
復制代碼
二、如何切換 Client
Feign 中自帶的是 HttpURLConnection,這個 client 健壯性差,可替換為成熟的 Apache HttpClient 或 OkHttp 來進行網絡請求。
2.1 使用 Apache 的 HTTP Client
使用 Apache 的 httpclient 替換 Feign 中默認的 client。
2.1.1 添加依賴
<!--httpclient的依賴,因為選擇了使用httpclient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>10.4.0</version>
</dependency>
復制代碼
2.1.2 配置啟用
配置中添加如下信息,表示啟用httpclient。
feign:
httpclient:
enabled: true
復制代碼
2.2 使用 OkHttp
2.2.1 添加依賴
在 Feign 中使用OkHttp作為網絡請求框架,則只需要在 pom 文件中加上feign-okhttp的依賴,代碼如下:
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.2.0</version>
</dependency>
復制代碼
2.2.2 配置啟用
feign:
okhttp:
enabled: true
復制代碼
三、如何修改日志級別
在發送和接收請求的時候,其內部將日志的打印輸出定義成了四個等級,對應的詳情如下:
級別 |
說明 |
NONE |
不做任何記錄 |
BASIC |
僅記錄請求方法和 URL 以及響應狀態代碼和執行時間 |
HEADERS |
記錄基本信息以及請求和響應標頭 |
FULL |
記錄請求和響應的標題,正文和元數據 |
3.1 通過配置文件修改日志級別
注意需要指定接口的全限定名
logging:
level:
com.zto.titans.test.feign.service.TestService : DEBUG
復制代碼
3.2 通過配置類修改日志級別
@Configuration
public class FooConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
復制代碼
這個一看即懂,不再廢話。
四、如何實現數據壓縮
可以分別對 HTTP 通信的request和response設置是否啟用 GZIP 壓縮,配置方法如下:
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json # 配置壓縮支持的MIME TYPE
min-request-size: 2048 # 配置壓縮數據大小的下限
response:
enabled: true # 配置響應GZIP壓縮
復制代碼
五、FeignClient 的配置以及配置的優先級機制
有 2 種途徑設置 FeignClient 的配置,通過自定義配置類來設置配置和在配置文件中設置,其中配置文件方式有點特殊,它里邊可以指定全局配置對所有 FeignClient 有效,也可以為特定名稱的 FeignClient 設置專屬的配置。
5.1 通過自定義配置類來定制配置
實現一個配置類
public class TestConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
復制代碼
將配置類 TestConfiguration 指定給configuration。
@FeignClient(
name = "test-service",
configuration = {FeignInterceptor2.class,TestConfiguration.class}
)
復制代碼
5.2 在配置文件中設置全局配置
feign.client.config.default.xxx ,這個default意為全局的配置屬性。
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
復制代碼
5.3 在配置文件中設置專屬配置
feign.client.config.feignName.xxx , 給名字為feignName的FeignClient指定專屬的配置。
feign:
client:
config:
feignName:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
errorDecoder: com.example.SimpleErrorDecoder
retryer: com.example.SimpleRetryer
requestInterceptors:
- com.example.FooRequestInterceptor
- com.example.BarRequestInterceptor
decode404: false
encoder: com.example.SimpleEncoder
decoder: com.example.SimpleDecoder
復制代碼
5.4 理解配置的優先級與攔截器的追加原則
從
org.springframework.cloud.openfeign.FeignClientFactoryBean#configureFeign中可以確認以上 3 種配置的優先級:
configureUsingConfiguration(context, builder); // 1
configureUsingProperties(properties.getConfig().get(properties.getDefaultConfig()),builder); //2
configureUsingProperties(properties.getConfig().get(this.contextId),builder);//3
復制代碼
- 第 1 類為通過自定義配置類來指定配置
- 第 2 類為在配置文件中的feign.client.config.default.xxx設置全局配置
- 第 3 類為在配置文件中的feign.client.config.feignName.xxx設置專屬配置
5.4.1 優先級的效果
配置文件里的專屬配置 -覆蓋-> 配置文件里的全局配置 -覆蓋-> 配置類的配置
5.4.2 追加的原則
RequestInterceptor 是攔截器,可以在發送前做一些處理,比如統一添加header信息。每一類中的requestInterceptors可以存儲多個攔截器,攔截器并非覆蓋的效果,而是鏈式追加的效果;從執行順序來看優先級是:1 > 2 > 3,即先執行 配置類中指定的攔截器,然后是 配置文件中指定的全局攔截器,最后是配置文件中指定的專屬攔截器。
需特別注意:RequestInterceptor 的實現類(例如 RI-A,RI-B)上如果添加了@Component注解,就都會被掃描識別到,并被追加到第一類的requestInterceptors列表中;倘若不小心 RI-A 還在第 2 類中又被指定了,則還會將攔截器 RI-A 追加在第二類的requestInterceptors列表中,結果是會 RI-A 總計會執行 2 次;若也在第三類中指定 RI-A,則 RI-A 也在其列表中追加,結果是 RI-A 總計會執行 3 次。
5.4.3 攔截器的效果驗證
以一個實例來驗證說明效果
- 自定義三個 RequestInterceptor
class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("user", "myuser1");
requestTemplate.header("password", "mypassword");
}
}
復制代碼
class FeignInterceptor1 implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("user1", "myuser1");
requestTemplate.header("password1", "mypassword1");
}
}
復制代碼
class FeignInterceptor2 implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("user2", "myuser2");
requestTemplate.header("password2", "mypassword2");
}
}
復制代碼
- @FeignClient 中指定一個
@FeignClient(
name = "test-service",
url = "http://localhost:8080/feign/server/",
configuration = {FeignInterceptor.class,TestConfiguration.class},
fallback = TestService.DefaultFallback.class
)
復制代碼
- 配置中指定 2 個
default 指定了一個,test-service里指定一個
feign:
httpclient:
enabled: true
okhttp:
enabled: true
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
#loggerLevel: none
requestInterceptors:
- com.zto.titans.test.feign.service.FeignInterceptor1
test-service:
#loggerLevel: basic
requestInterceptors:
- com.zto.titans.test.feign.service.FeignInterceptor2
logging:
level:
com.zto.titans.test.feign.service.TestService : DEBUG
復制代碼
根據追加邏輯,最終執行的順序是:
- FeignInterceptor
- FeignInterceptor1
- FeignInterceptor2
總結
本篇主要介紹 SpringBoot 中要玩轉 Feign 需要掌握的如添加 pom 依賴、客戶端注解啟用、切換底層 HttpClient、配置數據壓縮、調整日志級別、定制配置、配置的優先級機制、增加攔截器以及攔截器的追加機制等知識,以實例 + 效果的方式幫讀者高效全面并深入的理解它們。
原文鏈接:
https://juejin.cn/post/7169549885723639838
來源:稀土掘金