SpringCloud OpenFeign使用詳解
一、前言
在springcloud微服務(wù)生態(tài)體系下,作為服務(wù)之間相互調(diào)用的重要組件openfeign,在其中承擔(dān)著非常重要的作用,本篇以springcloud中提供的遠(yuǎn)程接口調(diào)用組件openfeign為例,來聊聊openfeign的詳細(xì)使用。
二、什么是openfeign
2.1 openfeign介紹
- Feign是Netflix開發(fā)的,聲明式、模板化的HTTP客戶端;
- Feign可幫助開發(fā)者更加便捷、優(yōu)雅地調(diào)用HTTP API;
- Feign支持多種注解,例如Feign自帶的注解或者JAX-RS注解等;
2.2 openfeign優(yōu)勢
Feign可以做到使用 HTTP 請求遠(yuǎn)程服務(wù)時(shí)就像調(diào)用本地方法一樣,開發(fā)者完全感知不到這是遠(yuǎn)程調(diào)用,更感知不到這是個(gè) HTTP 請求。具體來說:
- 它像 Dubbo 一樣,consumer 直接調(diào)用接口方法調(diào)用 provider,而不需要通過常規(guī)的 Http Client 構(gòu)造請求再解析返回?cái)?shù)據(jù);
- 它解決了讓開發(fā)者調(diào)用遠(yuǎn)程接口就跟調(diào)用本地方法一樣,無需關(guān)注與遠(yuǎn)程的交互細(xì)節(jié),更無需關(guān)注分布式環(huán)境開發(fā);
三、Spring Cloud Alibaba整合OpenFeign
以之前的工程案例為基座,在此基礎(chǔ)上繼續(xù)搭建新的模塊,接下來,通過實(shí)際的操作,演示如何基于Spring Cloud Alibaba實(shí)現(xiàn)與OpenFeign的整合
3.1 前置準(zhǔn)備
創(chuàng)建一個(gè)新的order模塊,名為:openfign-order,工程目錄如下
3.2 代碼整合過程
3.2.1 添加feign依賴
添加如下依賴,主要是open-feign的依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--nacos-config 配置中心-自帶動(dòng)態(tài)刷新--> <!--<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> </dependency>--> <!--nacos-discovery 注冊中心-服務(wù)發(fā)現(xiàn)與注冊--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies>
3.2.2 添加feign接口類
使用過dubbo的同學(xué)應(yīng)該對此不陌生,使用服務(wù)端提供的接口時(shí)只需要注入就可以像調(diào)用本地方法一樣使用了,feign的使用也是類似,只需在調(diào)用方定義一個(gè)接口類,里面添加被調(diào)用的接口中的完整的方法名,參數(shù)等,即保持與接口中的方法體參數(shù)一致即可;
比如在order模塊調(diào)用stock模塊時(shí),stock的接口類提供了下面的方法
@GetMapping("/reduct") public String reduct(){ System.out.println("扣減庫存 : 8021"); return "扣減庫存 : 8021"; }
那么在order模塊中,自定義一個(gè)接口類,如下
@FeignClient(name = "stock-service",path = "/stock") public interface StockFeignService { @GetMapping("/reduct") public String reduct(); }
參數(shù)說明:
- 該接口中的方法名,參數(shù),請求類型等都與接口提供方接口保持一致;
- 接口上面用FeignClient注解修飾,name為服務(wù)提供方名稱,path為接口根路徑;
3.2.3 調(diào)整調(diào)用的方法
在之前的調(diào)用中,我們一直使用的是restTemplate的方式調(diào)用,如果使用了feign,調(diào)用看起來就變得簡單了,做一下簡單的改造即可;
@RestController @RequestMapping("/order") public class OrderController { @Value("${service-url.nacos-user-service}") private String serverURL; @Autowired private StockFeignService stockFeignService; //localhost:8083/order/add @GetMapping("/add") public String add(){ System.out.println("下單成功"); String reduct = stockFeignService.reduct(); return "add order :" + reduct; } }
3.2.4 核心配置文件
這里調(diào)整一下端口即可
server: port: 8040 spring: application: name: order-service cloud: nacos: discovery: server-addr: localhost:8848 #服務(wù)注冊中心地址
3.2.5 接口模擬測試
啟動(dòng)stock-service的兩個(gè)工程,再啟動(dòng)order模塊,啟動(dòng)完成后,瀏覽器進(jìn)行接口調(diào)用
反復(fù)多次調(diào)用,默認(rèn)情況下,呈現(xiàn)出的是輪詢效果
四、openfeign自定義配置使用
Feign 提供了很多擴(kuò)展機(jī)制,開發(fā)者可以使用這些機(jī)制更靈活的擴(kuò)展系統(tǒng)功能。
4.1 擴(kuò)展日志配置 — 全局配置
使用了Feign之后,有時(shí)開發(fā)過程中遇到Bug,比如接口調(diào)用失敗、參數(shù)沒收到等問題,或者想看看調(diào)用性能,這就需要配置Feign的日志了,以便讓Feign把請求的完整信息輸出來定位和分析問題。配置過程很簡單,只需添加一個(gè)配置類, 定制Feign提供的Logger級別即可。
4.1.1 添加一個(gè)日志配置類
添加如下配置類,指定level的級別為FULL,表示輸出完整的日志信息
import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
也可以根據(jù)自身的需求配置其他的日志級別,從源碼中可以看到內(nèi)置了多種級別的日志
4.1.2 配置文件調(diào)整日志級別
默認(rèn)情況下,服務(wù)工程以info級別輸出,但Feign的日志級別為debug,兩者不匹配,所以還需要額外做一下配置,在配置文件中補(bǔ)充下面的配置即可,即針對
logging: level: com.congge.feign: debug
4.1.3 接口測試
在order模塊的Feign中添加一個(gè)新的接口進(jìn)行調(diào)用
@GetMapping("/get") public String get(@RequestParam("id") Integer id);
接口調(diào)用
//localhost:8040/order/get @GetMapping("/get") public String get(){ String stockInfo = stockFeignService.get(1); return stockInfo; }
瀏覽器執(zhí)行調(diào)用:localhost:8040/order/get,說明調(diào)用成功
再看控制臺(tái),發(fā)現(xiàn)輸出了詳細(xì)的調(diào)用日志信息
4.2 擴(kuò)展日志配置之局部配置
上面配置的這種方式是針對全局生效的,即Feign包路徑下的所有類都生效,如果僅僅是針對某個(gè)具體的類生效,該怎么做呢?其實(shí)也很簡單,只需要下面的兩步;
4.2.1 自定義日志配置類
與上面的想必,去掉那個(gè)@Configuration注解即可
import feign.Logger; import org.springframework.context.annotation.Bean; public class FeignConfig { @Bean public Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }
4.2.2 在目標(biāo)Feign接口指定日志配置類
在@FeignClient注解中有一個(gè)configuration的熟悉,使用上面的配置類即可
@FeignClient(name = "stock-service",path = "/stock",configuration = FeignConfig.class) public interface StockFeignService { @GetMapping("/reduct") public String reduct(); @GetMapping("/get") public String get(@RequestParam("id") Integer id); }
4.2.3 配置文件方式實(shí)現(xiàn)局部日志擴(kuò)展
在5.2.1的基礎(chǔ)上,也可以不用通過5.2.2的方式通過指定配置類添加,而是在配置文件中指定,只需要在配置文件中添加下面的配置即可;
feign: client: config: stock-service: loggerLevel: FULL
配置完成后再次調(diào)用一下,控制臺(tái)仍然可以輸出完整的調(diào)用日志信息
五、openfeign契約配置
Spring Cloud 在 Feign 的基礎(chǔ)上做了擴(kuò)展,使用 Spring MVC 的注解來完成Feign的功能,以減少使用者的學(xué)習(xí)成本。
而原生的 Feign 是不支持 Spring MVC 注解的,如果你想在 Spring Cloud 中使用原生的注解方式來定義客戶端也是可以的,通過配置契約來改變這個(gè)配置,Spring Cloud 中默認(rèn)的
是 SpringMvcContract。
Spring Cloud 1 早期版本就是用的原生Fegin. 隨著netflix的停更替換成了Open feign
5.1 具體操作步驟
5.1.1 使用配置類的方式
在配置類中添加Contract 的bean
@SpringBootApplication //@EnableDiscoveryClient @EnableFeignClients public class FeignOrderApp { public static void main(String[] args) { SpringApplication.run(FeignOrderApp.class, args); } @Bean public Contract feignContract() { return new Contract.Default(); } }
5.1.2 修改Feign接口的方法調(diào)用
注意:修改契約配置后,OrderFeignService 不再支持springmvc的注解,需要使用Feign原生的注解
接口中的調(diào)用改為如下(更多語法配置可以參閱相關(guān)資料)
@FeignClient(name = "stock-service",path = "/stock") public interface StockFeignServiceV2 { @RequestLine("GET /reduct") public String reduct(); @RequestLine("GET /get") public String get(@Param("id") Integer id); }
5.1.3 模擬測試
再次啟動(dòng)order模塊服務(wù),然后在瀏覽器調(diào)用
5.1.4 通過yml配置文件配置契約
在5.1.1 基礎(chǔ)上,將契約的配置配置到配置文件中也可以實(shí)現(xiàn)相同的效果,具體配置如下
feign: client: config: stock-service: loggerLevel: FULL #配置契約 concontract: feign.Contract.Default
六、openfeign超時(shí)配置
客戶端微服務(wù)通過Fiegn調(diào)用其他微服務(wù)接口時(shí),可能因?yàn)槟承┰驅(qū)е陆涌陧憫?yīng)超時(shí)達(dá)到默認(rèn)的設(shè)置時(shí)間而調(diào)用失敗,如果業(yè)務(wù)允許超時(shí)時(shí)長更長一點(diǎn)的話,就可以考慮手動(dòng)配置openfeign的超時(shí)時(shí)間;
6.1 通過代碼方式配置
在上述的配置類中添加下面的超時(shí)配置bean;
- 通過 Options 可以配置連接超時(shí)時(shí)間和讀取超時(shí)時(shí)間;
- Options 的第一個(gè)參數(shù)是連接的超時(shí)時(shí)間(ms),默認(rèn)值是 2s;
- Options 的第一個(gè)參數(shù)是連接的超時(shí),第二個(gè)是請求處理的超時(shí)時(shí)間(ms),默認(rèn)值是 5s;
@Bean public Request.Options options() { return new Request.Options(5000, 10000); }
6.2 通過配置文件方式配置
6.2.1 添加配置文件
核心配置如下
feign: client: config: stock-service: loggerLevel: FULL #配置契約 #concontract: feign.Contract.Default connectTimeout: 5000 readTimeout: 3000
補(bǔ)充說明: Feign的底層用的是Ribbon,但超時(shí)時(shí)間以Feign配置為準(zhǔn)
6.2.2 修改被調(diào)用方接口
為了模擬效果,將調(diào)用的stock-service中的接口加一個(gè)sleep時(shí)間
@GetMapping("/get") public String get(@RequestParam("id") Integer id) throws InterruptedException { Thread.sleep(4000); return "查詢到的庫存商品ID : " + id; }
6.2.3 模擬測試調(diào)用
啟動(dòng)兩個(gè)模塊的工程,瀏覽器調(diào)用接口:localhost:8040/order/get,將會(huì)看到下面的效果
同時(shí)觀察控制臺(tái)輸出日志,可以看到輸出了 超時(shí)的信息;
?七、openfeign 自定義攔截器
7.1 攔截器概述
使用springmvc攔截器的同學(xué)對攔截器應(yīng)該不陌生,攔截器可以在請求真正到達(dá)后端接口之前做一下預(yù)處理工作,比如非法請求攔截、參數(shù)校驗(yàn)過濾、全局token的認(rèn)證、加解密、審計(jì)等等。在openfeign 中也提供了類似的可以自定義的攔截器,其存在的目的主要是針對服務(wù)調(diào)用端在調(diào)用服務(wù)接口時(shí)可以做的一些預(yù)處理工作。
接下來演示如何在openfeign 中自定義攔截器;
7.2 操作過程
7.2.1 自定義 FeignInterceptor
主要是實(shí)現(xiàn)RequestInterceptor 接口,重寫里面的apply方法即可,比如在下面的apply方法中,給請求頭中添加了兩個(gè)參數(shù),這樣的話,服務(wù)提供方就可以解析到header中參數(shù)的值;
import feign.RequestInterceptor; import feign.RequestTemplate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.UUID; public class FeignInterceptor implements RequestInterceptor { static final Logger logger = LoggerFactory.getLogger(FeignInterceptor.class); @Override public void apply(RequestTemplate requestTemplate) { logger.info("enter FeignInterceptor ..."); String accessToken=UUID.randomUUID().toString(); requestTemplate.header("accessToken",accessToken); requestTemplate.header("username","jerry"); } }
7.2.2 使自定義的攔截器生效
可以通過配置全局bean的方式或者在yaml中配置都可以
配置bean的方式
@Bean public FeignInterceptor feignInterceptor() { return new FeignInterceptor(); }
配置文件方式
feign: client: config: stock-service: loggerLevel: FULL connectTimeout: 5000 readTimeout: 3000 #自定義攔截器 requestInterceptors: com.congge.config.FeignInterceptor
7.2.3 改造stock中的get接口
這里將請求中的參數(shù)進(jìn)行解析,并打印輸出結(jié)果
@GetMapping("/get") public String get(@RequestParam("id") Integer id) throws InterruptedException { String accessToken = request.getHeader("accessToken"); System.out.println(accessToken); String username = request.getHeader("username"); System.out.println(username); //Thread.sleep(4000); return "查詢到的庫存商品ID : " + id; }
7.2.4 模擬測試
分別啟動(dòng)stock模塊的工程和order模塊的工程,然后瀏覽器調(diào)用:localhost:8040/order/get
接口可以正常返回結(jié)果;
?觀察stock服務(wù)控制臺(tái),header中的參數(shù)值也能正確的被解析出來;
?7.2.5 自定義攔截器小結(jié)
自定義攔截器一種很有用的技巧,尤其是內(nèi)部各個(gè)微服務(wù)之間進(jìn)行調(diào)用的時(shí)候,為了確認(rèn)對方的身份是否授信或者互信,可以通過這種方式傳遞一些可以加解密的參數(shù)進(jìn)行身份確認(rèn)。
八、寫在文末
Feign在springcloud微服務(wù)生態(tài)體系中具有非常重要的作用,對于習(xí)慣使用dubbo服務(wù)調(diào)用方式的同學(xué)來說,系統(tǒng)在微服務(wù)架構(gòu)演進(jìn)過程中,可以采用同時(shí)兼容dubbo和feign的方式,而且只需要在現(xiàn)用的架構(gòu)中做少量的適配和改造即可,這是一個(gè)很好的嘗試,因此有必要深入了解Feign的技術(shù)。
以上就是SpringCloud OpenFeign使用詳解的詳細(xì)內(nèi)容,更多關(guān)于SpringCloud OpenFeign使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringSecurity多表多端賬戶登錄的實(shí)現(xiàn)
本文主要介紹了SpringSecurity多表多端賬戶登錄的實(shí)現(xiàn)2024-05-05關(guān)于訪問后端接口報(bào)404錯(cuò)誤問題的解決方法(全網(wǎng)最細(xì)!)
404頁面的出現(xiàn)會(huì)降低用戶體驗(yàn),那么導(dǎo)致404頁面出現(xiàn)的原因是什么呢?這篇文章主要給大家介紹了關(guān)于訪問后端接口報(bào)404錯(cuò)誤問題的解決方法,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-04-04詳解在SpringBoot中使用MongoDb做單元測試的代碼
這篇文章主要介紹了詳解在SpringBoot中使用MongoDb做單元測試的代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11SpringBoot?DataSource數(shù)據(jù)源實(shí)現(xiàn)自動(dòng)配置流程詳解
這篇文章主要介紹了SpringBoot?DataSource數(shù)據(jù)源實(shí)現(xiàn)自動(dòng)配置流程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-10-10MyBatisPlus中事務(wù)處理的實(shí)現(xiàn)
本文主要介紹了MyBatisPlus中事務(wù)處理的實(shí)現(xiàn),包括事務(wù)的開啟、提交、回滾等操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-07-07Spring boot @RequestBody數(shù)據(jù)傳遞過程詳解
這篇文章主要介紹了Spring boot @RequestBody數(shù)據(jù)傳遞過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12java 高并發(fā)中volatile的實(shí)現(xiàn)原理
這篇文章主要介紹了java 高并發(fā)中volatile的實(shí)現(xiàn)原理的相關(guān)資料,在多線程并發(fā)編程中synchronized和Volatile都扮演著重要的角色,Volatile是輕量級的synchronized,它在多處理器開發(fā)中保證了共享變量的“可見性”,需要的朋友可以參考下2017-03-03