一文教你如何使用原生的Feign
什么是Feign
Feign 是由 Netflix 團(tuán)隊(duì)開發(fā)的一款基于 Java 實(shí)現(xiàn)的 HTTP client,借鑒了 Retrofit、 JAXRS-2.0、WebSocket 等類庫。通過 Feign,我們可以像調(diào)用方法一樣非常簡單地訪問 HTTP API。這篇博客將介紹如何使用原生的 Feign,注意,是原生的,不是經(jīng)過 Spring 層層封裝的 Feign。
補(bǔ)充一下,在 maven 倉庫中搜索 feign,我們會看到兩種 Feign: OpenFeign Feign 和 Netflix Feign。它們有什么區(qū)別呢?簡單地說,OpenFeign Feign 的前身就是 Netflix Feign,因?yàn)?Netflix Feign 從 2016 年開始就不維護(hù)了,所以建議還是使用 OpenFeign Feign。
為什么使用Feign
為什么要使用HTTP client
首先,因?yàn)?Feign 本身是一款 HTTP client,所以,這里先回答:為什么使用 HTTP client?
假設(shè)不用 HTTP client,我們訪問 HTTP API 的過程大致如下。是不是相當(dāng)復(fù)雜呢?直接操作 socket 已經(jīng)非常麻煩了,我們還必須在熟知 HTTP 協(xié)議的前提下自行完成報(bào)文的組裝和解析,代碼的復(fù)雜程度可想而知。
那么,這個過程是不是可以更簡單一些呢?
我們可以發(fā)現(xiàn),在上面的圖中,紅框的部分是相對通用的,是不是可以把這些邏輯封裝起來?基于這樣的思考,于是就有了 HTTP client(根據(jù)類庫的不同,封裝的層次會有差異)。
所以,為什么要使用 HTTP client 呢?簡單地說,就是為了讓我們更方便地訪問 HTTP API。
為什么要使用Feign
HTTP client 的類庫還有很多,例如 Retrofit、JDK 自帶的 HttpURLConnection、Apache HttpClient、OkHttp、Spring 的 RestTemplate,等等。我很少推薦說要使用哪種具體的類庫,如果真的要推薦 Feign 的話,主要是由于它優(yōu)秀的擴(kuò)展性(不是一般的優(yōu)秀,后面的使用例子就可以看到)。
如何使用Feign
關(guān)于如何使用 Feign,官方給出了非常詳細(xì)的文檔,在我看過的第三方類庫中,算是比較少見的。
本文用到的例子也是參考了官方文檔。
項(xiàng)目環(huán)境說明
os:win 10
jdk:1.8.0_231
maven:3.6.3
IDE:Spring Tool Suite 4.6.1.RELEASE
引入依賴
這里引入 gson,是因?yàn)槿腴T例子需要有一個 json 解碼器。
<properties> <feign.version>11.2</feign.version> </properties> <dependencies> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-core</artifactId> <version>${feign.version}</version> </dependency> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-gson</artifactId> <version>${feign.version}</version> </dependency> </dependencies>
入門例子
入門例子中使用 Feign 來訪問 github 的接口獲取 Feign 這個倉庫的所有貢獻(xiàn)者。
通過下面的代碼可以發(fā)現(xiàn),F(xiàn)eign 本質(zhì)上是使用了動態(tài)代理來生成訪問 HTTP API 的代碼,定義 HTTP API 的過程有點(diǎn)像在定義 advice。
// 定義HTTP API interface GitHub { @RequestLine("GET /repos/{owner}/{repo}/contributors") // @RequestLine(value = "GET /repos/{owner}/{repo}/contributors", decodeSlash = false)// 測試轉(zhuǎn)義"/"、"+" // @RequestLine("GET /repos/{owner:[a-zA-Z]*}/{repo}/contributors")// 測試正則校驗(yàn) // @Headers("Accept: application/json") // 測試添加header List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); } public static class Contributor { String login; int contributions; } public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new GsonDecoder()) // 返回內(nèi)容為json格式,所以需要用到j(luò)son解碼器 // .options(new Request.Options(10, TimeUnit.SECONDS, 60, TimeUnit.SECONDS, true)) // 配置超時(shí)參數(shù)等 .target(GitHub.class, "https://api.github.com"); // 像調(diào)用方法一樣訪問HTTP API github.contributors("OpenFeign", "feign").stream() .map(contributor -> contributor.login + " (" + contributor.contributions + ")") .forEach(System.out::println); } }
個性化配置
除了簡單方便之外,F(xiàn)eign 還有一個很大的亮點(diǎn),就是有相當(dāng)優(yōu)秀的擴(kuò)展性,幾乎什么都可以自定義。下面是官方給的一張圖,基本涵蓋了 Feign 可以擴(kuò)展的內(nèi)容。每個擴(kuò)展支持都有一個對應(yīng)的適配包,例如,更換解碼器為 jackson 時(shí),需要引入io.github.openfeign:feign-jackson的適配包。
更換為Spring的注解
在入門例子中,我們使用 Feign 自帶的注解來定義 HTTP API。但是,對于習(xí)慣了 Spring 注解的許多人來說,無疑需要增加學(xué)習(xí)成本。我們自然會問,F(xiàn)eign 能不能支持 Spring 注解呢?答案是肯定的。Feign 不但能支持 Spring 注解,還可以支持 JAX-RS、SOAP 等等。
下面就是使用 Sping 注解定義 HTTP API 的例子。注意,pom 文件中要引入 io.github.openfeign:feign-spring4 的依賴。
// 定義HTTP API interface GitHub { @GetMapping("/repos/{owner}/{repo}/contributors") List<Contributor> contributors(@RequestParam("owner") String owner, @RequestParam("repo") String repo); } public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new GsonDecoder()) .contract(new SpringContract())// 自定義contract .target(GitHub.class, "https://api.github.com"); } }
自定義解碼器和編碼器
在入門例子中,我們使用 gson 來解析 json。那么,如果我想把它換成 jackson 行不行?Feign 照樣提供了支持。
注意,pom 文件中要引入 io.github.openfeign:feign-jackson 的依賴。
public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new JacksonDecoder()) // 自定義解碼器 .encoder(new JacksonEncoder()) // 自定義編碼器 .target(GitHub.class, "https://api.github.com"); } }
自定義內(nèi)置的HTTP client
接下來的這個自定義就更厲害了。Feign 本身作為一款 HTTP client,竟然還可以支持其他 HTTP client。
這里用 OkHttp 作例子。注意,pom 文件中要引入 io.github.openfeign:feign-okhttp 的依賴。
public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new GsonDecoder()) .client(new OkHttpClient())// 自定義client .target(GitHub.class, "https://api.github.com"); } }
自定義攔截器
我們訪問外部接口時(shí),有時(shí)需要帶上一些特定的 header,例如,應(yīng)用標(biāo)識、token,我們可以通過兩種方式實(shí)現(xiàn):一是使用注解定義 HTTP API,二是使用攔截器(更常用)。下面的例子中,使用攔截器給請求添加 token 請求頭。
public class MyInterceptor implements RequestInterceptor { @Override public void apply(RequestTemplate template) { template.header("token", LoginUtils.getCurrentToken()); } } public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new GsonDecoder()) .requestInterceptor(new MyInterceptor()) .target(GitHub.class, "https://api.github.com"); } }
自定義重試器
默認(rèn)情況下,F(xiàn)eign 訪問 HTTP API 時(shí),如果拋出IOException,它會認(rèn)為是短暫的網(wǎng)絡(luò)異常而發(fā)起重試,這時(shí),F(xiàn)eign 會使用默認(rèn)的重試器feign.Retryer.Default(最多重試 5 次),如果不想啟用重試,則可以選擇另一個重試器feign.Retryer.NEVER_RETRY。當(dāng)然,我們也可以自定義。
奇怪的是,F(xiàn)eign 通過重試器的 continueOrPropagate(RetryableException e)方法是否拋出RetryableException來判斷是否執(zhí)行重試,為什么不使用 true 或 false 來判斷呢?
注意,重試器是用來判斷是否執(zhí)行重試,自身不包含重試的邏輯。
public class MyRetryer implements Retryer { int attempt = 0; @Override public void continueOrPropagate(RetryableException e) { // 如果把RetryableException拋出,則不會繼續(xù)重試 // 否則繼續(xù)重試 if(attempt++ >= 3) {// 重試三次 throw e; } } @Override public Retryer clone() { return this; } } public class MyApp { public static void main(String... args) { // 獲取用來訪問HTTP API的代理類 GitHub github = Feign.builder() .decoder(new GsonDecoder()) .retryer(new MyRetryer()) //.retryer(Retryer.NEVER_RETRY) // 不重試 .exceptionPropagationPolicy(ExceptionPropagationPolicy.UNWRAP) .target(GitHub.class, "https://api.github.com"); } }
結(jié)語
以上,基本講完 Feign 的使用方法,其實(shí) Feign 還有其他可以擴(kuò)展的東西,例如,斷路器、監(jiān)控等等。感興趣的話,可以自行分析。
到此這篇關(guān)于如何使用原生的Feign的文章就介紹到這了,更多相關(guān)使用原生的Feign內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
參考資料
相關(guān)源碼請移步:https://github.com/ZhangZiSheng001/feign-demo
相關(guān)文章
Java中的Set接口實(shí)現(xiàn)類HashSet和LinkedHashSet詳解
這篇文章主要介紹了Java中的Set接口實(shí)現(xiàn)類HashSet和LinkedHashSet詳解,Set接口和java.util.List接口一樣,同樣繼承自Collection接口,它與Collection接口中的方法基本一致,并沒有對Collection接口進(jìn)行功能上的擴(kuò)充,只是比Collection接口更加嚴(yán)格了,需要的朋友可以參考下2024-01-01java構(gòu)造函數(shù)示例(構(gòu)造方法)
這篇文章主要介紹了java構(gòu)造函數(shù)示例(構(gòu)造方法),需要的朋友可以參考下2014-03-03SpringCloud Config統(tǒng)一配置中心問題分析解決與客戶端動態(tài)刷新實(shí)現(xiàn)
springcloud config是一個解決分布式系統(tǒng)的配置管理方案。它包含了 client和server兩個部分,server端提供配置文件的存儲、以接口的形式將配置文件的內(nèi)容提供出去,client端通過接口獲取數(shù)據(jù)、并依據(jù)此數(shù)據(jù)初始化自己的應(yīng)用2022-10-10SpringCloud Feign配置應(yīng)用詳細(xì)介紹
這篇文章主要介紹了SpringCloud Feign配置應(yīng)用,feign是netflix提供的服務(wù)間基于http的rpc調(diào)用框架,在spring cloud得到廣泛應(yīng)用2022-09-09swagger2隱藏在API文檔顯示某些參數(shù)的操作
這篇文章主要介紹了swagger2隱藏在API文檔顯示某些參數(shù)的操作,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06使用Spring特性實(shí)現(xiàn)接口多實(shí)現(xiàn)類的動態(tài)調(diào)用方式
這篇文章主要介紹了使用Spring特性實(shí)現(xiàn)接口多實(shí)現(xiàn)類的動態(tài)調(diào)用方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02Java中String.split()的最詳細(xì)源碼解讀及注意事項(xiàng)
以前經(jīng)常使用String.split()方法,但是從來沒有注意,下面這篇文章主要給大家介紹了關(guān)于Java中String.split()最詳細(xì)源碼解讀及注意事項(xiàng)的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07