天天看點

撸了一個 Feign 增強包

撸了一個 Feign 增強包

最近準備将公司的一個核心業務系統用 <code>Java</code> 進行重構,大半年沒寫 <code>Java</code> ,<code>JDK</code> 都更新到 14 了,考慮到穩定性等問題最終還是選擇的 <code>JDK11</code>。

在整體架構選型時,由于是一個全新的系統,是以沒有曆史包袱,同時團隊中也有多位大牛坐鎮,是以我們的選項便大膽起來。

最終結果就是直接一把梭,直接上未來的大趨勢:<code>Service Mesh</code>,直接把什麼 <code>SpringCloud</code>、<code>Dubbo</code> 這類分布式架構全部幹掉。

本次的重點不是讨論 <code>Service Mesh</code> 是什麼、能解決什麼問題、為什麼選擇它,畢竟我也在學習階段,啥時候整明白線上也穩定了再和大家來交流。

既然方向定了就開始實際撸碼了,不過剛一開始就驗證了”理想很豐滿、現實很骨感“;

由于我們去掉了 <code>SpringCloud</code> 和 <code>Dubbo</code> 這類架構,服務的注冊、發現、負載均衡等需求全部都下沉到 <code>Service Mesh</code> 中提供了。

但對于開發來說依然希望可以調用本地方法的方式來調用遠端服務,這在 <code>SpringCloud</code> 這類架構中是很容易實作的,架構本身就有很好的支援。

回到我們這個場景,需求其實很簡單,就是想達到 <code>SpringCloud</code> 中的 <code>Feign</code> 這樣的聲明式+注解的方式調用。

撸了一個 Feign 增強包

使用 <code>spring-cloud-openfeign</code> 這個包其實就能實作上述的需求了,但這樣會引入一些我們根本不會使用的 <code>SpringCloud</code> 的相關依賴,讓人感覺”不幹淨了“;同時也和 <code>Service Mesh</code> 的理念相反,其中的一大目的就是要降低這類架構的侵入性。

其實 <code>spring-cloud-openfeign</code> 的核心就是 Feign,本身它也是可以開箱即用的,是以便嘗試看 <code>Feign</code> 自己是否支援這樣的用法。

撸了一個 Feign 增強包

通過官方文檔可以得知:是可以定義接口的形式來調用遠端接口的,但它本質上是不依賴其他庫便可以使用,是以它本身是沒有和 <code>Spring</code> 整合也是合情合理,但也就造成了沒有現成庫可供我們使用。

我們自然是不想寫上圖紅框處的代碼的,希望所有接口直接注入就可以使用。

是以結合以上的需求便有了這個庫 feign-plus

它的使用流程其實就是翻版的 <code>spring-cloud-openfeign</code>:

在 <code>SpringBoot</code> 入口進行掃描:

在 <code>Spring</code> 上下文中直接注入使用:

是以當我們需要調用一些外部第三方接口時(比如支付寶、外部 OpenAPI)便可類似于這樣定義一個接口,把所有 HTTP 請求的細節屏蔽掉。

當然也适合公司内部之間的服務調用,和咱們以前寫 <code>SpringCloud</code> 或 <code>Dubbo</code> 時類似;服務提供方提供一個 <code>Client</code> 包,消費方直接依賴便可以調用。其他的負載均衡、容錯之類的由 <code>Service Mesh</code> 替我們完成。

對于内部接口,也可以加上 <code>@RequestMapping("/path")</code> 注解:

撸了一個 Feign 增強包

在請求時便會在 url 後拼接上 <code>/order</code>,這樣在配置 <code>feign.order.service.url</code> 時隻需要填入服務提供方的域名或 IP 即可。

<code>feign-plus</code> 也支援切換具體的 httpclient,預設是 <code>okhttp3</code>,通過以下配置便可更改。

當然也有其他相關配置:

最後簡單聊聊是如何完成的吧,其實本質上就是 <code>spring-cloud-openfeign</code> 的濃縮版。

其中最為核心的便是 <code>top.crossoverjie.feign.plus.factory.FeignPlusBeanFactory</code> 類。

撸了一個 Feign 增強包

該類實作了 <code>org.springframework.beans.factory.FactoryBean</code>接口,并重寫了 <code>getObject()</code> 方法傳回一個對象。

這段代碼是不是似曾相識,其實就是 <code>Feign</code> 的官方 <code>demo</code>。

這裡所傳回的對象其實就是我們定義的接口的代理對象,而這個對象本身則是 <code>Feign</code> ,是以再往裡說:我們的 <code>http</code> 請求編解碼、發起請求等邏輯又被這個 <code>feign</code> 對象所代理了。

撸了一個 Feign 增強包

這個 <code>HardCodedTarget</code> 則是 <code>Feign</code> 内部用于代理最終請求的對象。

有一個小難受的地方:這樣的自己定義 Bean 然後注入對象 Idea 是識别不了的,認為目前上下文沒有該 Bean,但是 spring-cloud-openfeign 卻可以識别。

由于 <code>Feign</code> 支援多個用戶端,是以這裡的用戶端可以通過配置檔案動态指定。

撸了一個 Feign 增強包

利用 <code>SpringBoot</code> 提供的 <code>@ConditionalOnExpression</code> 注解可以根據配置動态的選擇使用哪個 <code>httpclient</code>,也就是動态選擇生成哪個 <code>Bean</code>。

這個庫的邏輯非常簡單,本質上就是封裝了 <code>Feign</code> 并提供了 <code>SpringBoot</code> 的支援,歡迎有類似需求的朋友下載下傳使用。

<code>feign-plus</code>源碼:https://github.com/crossoverJie/feign-plus

你的點贊與分享是對我最大的支援

作者:

crossoverJie

出處:

https://crossoverjie.top

撸了一個 Feign 增強包

歡迎關注部落客公衆号與我交流。

本文版權歸作者所有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出,

如有問題, 可郵件(crossoverJie#gmail.com)咨詢。