代碼參考
Gitee:[https://gitee.com/xn2001/cloudcode/tree/master/06-cloud-feign](https://gitee.com/xn2001/cloudcode/tree/master/06-cloud-feign)
GitHub:[https://github.com/lexinhu/cloudcode/tree/master/06-cloud-feign](https://github.com/lexinhu/cloudcode/tree/master/06-cloud-feign)
我們以前利用 RestTemplate 發(fā)起遠程調(diào)用的代碼:
- 代碼可讀性差,編程體驗不統(tǒng)一
- 參數(shù)復(fù)雜URL難以維護
Feign 是一個聲明式的 http 客戶端,官方地址:https://github.com/OpenFeign/feign
其作用就是幫助我們優(yōu)雅的實現(xiàn) http 請求的發(fā)送畜号,解決上面提到的問題。
Feign使用
引入依賴
我們在 order-service 引入 feign 依賴:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
添加注解
在 order-service 啟動類添加注解開啟 Feign
請求接口
在 order-service 中新建一個接口,內(nèi)容如下
package com.xn2001.order.client;
import com.xn2001.order.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient("userservice")
public interface UserClient {
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
@FeignClient("userservice")
:其中參數(shù)填寫的是微服務(wù)名
@GetMapping("/user/{id}")
:其中參數(shù)填寫的是請求路徑
這個客戶端主要是基于 SpringMVC 的注解 @GetMapping 來聲明遠程調(diào)用的信息
Feign 可以幫助我們發(fā)送 http 請求,無需自己使用 RestTemplate 來發(fā)送了撮执。
測試
@Autowired
private UserClient userClient;
public Order queryOrderAndUserById(Long orderId) {
// 1.查詢訂單
Order order = orderMapper.findById(orderId);
// TODO: 2021/8/20 使用feign遠程調(diào)用
User user = userClient.findById(order.getUserId());
// 3. 將用戶信息封裝進訂單
order.setUser(user);
// 4.返回
return order;
}
自定義配置
Feign 可以支持很多的自定義配置,如下表所示:
一般情況下舷丹,默認值就能滿足我們使用抒钱,如果要自定義時,只需要創(chuàng)建自定義的 @Bean 覆蓋默認 Bean 即可颜凯。下面以日志為例來演示如何自定義配置继效。
基于配置文件修改 feign 的日志級別可以針對單個服務(wù):
feign:
client:
config:
userservice: # 針對某個微服務(wù)的配置
loggerLevel: FULL # 日志級別
也可以針對所有服務(wù):
feign:
client:
config:
default: # 這里用default就是全局配置,如果是寫服務(wù)名稱装获,則是針對某個微服務(wù)的配置
loggerLevel: FULL # 日志級別
而日志的級別分為四種:
- NONE:不記錄任何日志信息,這是默認值厉颤。
- BASIC:僅記錄請求的方法穴豫,URL以及響應(yīng)狀態(tài)碼和執(zhí)行時間
- HEADERS:在BASIC的基礎(chǔ)上,額外記錄了請求和響應(yīng)的頭信息
- FULL:記錄所有請求和響應(yīng)的明細逼友,包括頭信息精肃、請求體、元數(shù)據(jù)
也可以基于 Java 代碼來修改日志級別帜乞,先聲明一個類司抱,然后聲明一個 Logger.Level 的對象
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志級別為BASIC
}
}
如果要全局生效,將其放到啟動類的 @EnableFeignClients 這個注解中:
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
如果是局部生效黎烈,則把它放到對應(yīng)的 @FeignClient 這個注解中:
@FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class)
性能優(yōu)化
Feign 底層發(fā)起 http 請求习柠,依賴于其它的框架匀谣。其底層客戶端實現(xiàn)有:
- URLConnection:默認實現(xiàn),不支持連接池
- Apache HttpClient :支持連接池
- OKHttp:支持連接池
因此提高 Feign 性能的主要手段就是使用連接池代替默認的 URLConnection
另外资溃,日志級別應(yīng)該盡量用 basic/none武翎,可以有效提高性能。
這里我們用 Apache 的HttpClient來演示連接池溶锭。
在 order-service 的 pom 文件中引入 HttpClient 依賴
<!--httpClient的依賴 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
配置連接池
在 order-service 的 application.yml 中添加配置
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志級別宝恶,BASIC就是基本的請求和響應(yīng)信息
httpclient:
enabled: true # 開啟feign對HttpClient的支持
max-connections: 200 # 最大的連接數(shù)
max-connections-per-route: 50 # 每個路徑的最大連接數(shù)
最佳實踐
繼承方式
一樣的代碼可以通過繼承來共享:
1)定義一個 API 接口,利用定義方法趴捅,并基于 SpringMVC 注解做聲明
2)Feign 客戶端垫毙、Controller 都集成該接口
優(yōu)點
- 簡單
- 實現(xiàn)了代碼共享
缺點
- 服務(wù)提供方、服務(wù)消費方緊耦合
- 參數(shù)列表中的注解映射并不會繼承拱绑,因此 Controller 中必須再次聲明方法综芥、參數(shù)列表、注解
抽取方式
將 FeignClient 抽取為獨立模塊欺栗,并且把接口有關(guān)的 pojo毫痕、默認的 Feign 配置都放到這個模塊中,提供給所有消費者使用迟几。
例如:將 UserClient消请、User、Feign 的默認配置都抽取到一個 feign-api 包中类腮,所有微服務(wù)引用該依賴包臊泰,即可直接使用。
接下來我們就用該方法在代碼中實現(xiàn)
首先創(chuàng)建一個 module蚜枢,命名為 feign-api
在 feign-api 中然后引入依賴
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
order-service中 的 UserClient缸逃、User 都復(fù)制到 feign-api 項目中
接下來在 order-service 中使用 feign-api
由于我們已經(jīng)將 UserClient、User 放在 fegin-api 中共享了 厂抽,所以可以刪除 order-service 中的 UserClient需频、User,然后在 order-service 中引入 feign-api
<dependency>
<groupId>com.xn2001.feign</groupId>
<artifactId>feign-api</artifactId>
<version>1.0</version>
</dependency>
修改注解
當定義的 FeignClient 不在 SpringBootApplication 的掃描包范圍下時筷凤,這些 FeignClient 就不能使用昭殉。
修改 order-service 啟動類上的 @EnableFeignClients 注解
@EnableFeignClients(basePackages = "com.xn2001.feign.clients")