最近準備將公司的一個核心業務系統用 Java
進行重構,大半年沒寫 Java
,JDK
都更新到 14 了,考慮到穩定性等問題最終仍是選擇的 JDK11
。java
在總體架構選型時,因爲是一個全新的系統,因此沒有歷史包袱,同時團隊中也有多位大牛坐鎮,所以咱們的選項便大膽起來。git
最終結果就是直接一把梭,直接上將來的大趨勢:Service Mesh
,直接把什麼 SpringCloud
、Dubbo
這類分佈式框架所有幹掉。github
本次的重點不是討論 Service Mesh
是什麼、能解決什麼問題、爲何選擇它,畢竟我也在學習階段,啥時候整明白線上也穩定了再和你們來交流。spring
既然方向定了就開始實際擼碼了,不過剛一開始就驗證了」理想很豐滿、現實很骨感「;架構
因爲咱們去掉了 SpringCloud
和 Dubbo
這類框架,服務的註冊、發現、負載均衡等需求所有都下沉到 Service Mesh
中提供了。app
但對於開發來講依然但願能夠調用本地方法的方式來調用遠程服務,這在 SpringCloud
這類框架中是很容易實現的,框架自己就有很好的支持。負載均衡
回到咱們這個場景,需求其實很簡單,就是想達到 SpringCloud
中的 Feign
這樣的聲明式+註解的方式調用。框架
@Autowired private StoreClient client ; Store store = client.update(1, store)
使用 spring-cloud-openfeign
這個包其實就能實現上述的需求了,但這樣會引入一些咱們根本不會使用的 SpringCloud
的相關依賴,讓人感受」不乾淨了「;同時也和 Service Mesh
的理念相反,其中的一大目的就是要下降這類框架的侵入性。分佈式
其實 spring-cloud-openfeign
的核心就是 Feign,自己它也是能夠開箱即用的,因此便嘗試看 Feign
本身是否支持這樣的用法。學習
經過官方文檔能夠得知:是能夠定義接口的形式來調用遠程接口的,但它本質上是不依賴其餘庫即可以使用,因此它自己是沒有和 Spring
整合也是合情合理,但也就形成了沒有現成庫可供咱們使用。
咱們天然是不想寫上圖紅框處的代碼的,但願全部接口直接注入就可使用。
所以結合以上的需求便有了這個庫 feign-plus
它的使用流程其實就是翻版的 spring-cloud-openfeign
:
@FeignPlusClient(name = "github", url = "${github.url}") public interface Github { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<GitHubRes> contributors(@Param("owner") String owner, @Param("repo") String repo); }
在 SpringBoot
入口進行掃描:
@SpringBootApplication @EnableFeignPlusClients(basePackages = "top.crossoverjie.feign.test") public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
在 Spring
上下文中直接注入使用:
@Autowired private Github github ; List<GitHubRes> contributors = github.contributors("crossoverJie", "feign-plus"); logger.info("contributors={}", new Gson().toJson(contributors));
因此當咱們須要調用一些外部第三方接口時(好比支付寶、外部 OpenAPI)即可相似於這樣定義一個接口,把全部 HTTP 請求的細節屏蔽掉。
固然也適合公司內部之間的服務調用,和我們之前寫 SpringCloud
或 Dubbo
時相似;服務提供方提供一個 Client
包,消費方直接依賴即可以調用。其餘的負載均衡、容錯之類的由 Service Mesh
替咱們完成。
對於內部接口,也能夠加上 @RequestMapping("/path")
註解:
在請求時便會在 url 後拼接上 /order
,這樣在配置 feign.order.service.url
時只須要填入服務提供方的域名或 IP 便可。
feign-plus
也支持切換具體的 httpclient,默認是 okhttp3
,經過如下配置即可更改。
# default(okhttp3) feign.httpclient=http2Client
固然也有其餘相關配置:
feign.plus.max-idle-connections = 520 feign.plus.connect-timeout = 11000 feign.plus.read-timeout = 12000
最後簡單聊聊是如何完成的吧,其實本質上就是 spring-cloud-openfeign
的濃縮版。
其中最爲核心的即是 top.crossoverjie.feign.plus.factory.FeignPlusBeanFactory
類。
該類實現了 org.springframework.beans.factory.FactoryBean
接口,並重寫了 getObject()
方法返回一個對象。
這段代碼是否是似曾相識,其實就是Feign
的官方demo
。
這裏所返回的對象其實就是咱們定義的接口的代理對象,而這個對象自己則是 Feign
,因此再往裏說:咱們的 http
請求編解碼、發起請求等邏輯又被這個 feign
對象所代理了。
這個 HardCodedTarget
則是 Feign
內部用於代理最終請求的對象。
有一個小難受的地方:這樣的本身定義 Bean 而後注入對象 Idea 是識別不了的,認爲當前上下文沒有該 Bean,可是 spring-cloud-openfeign 卻能夠識別。
因爲 Feign
支持多個客戶端,因此這裏的客戶端能夠經過配置文件動態指定。
利用 SpringBoot
提供的 @ConditionalOnExpression
註解能夠根據配置動態的選擇使用哪一個 httpclient
,也就是動態選擇生成哪一個 Bean
。
這個庫的邏輯很是簡單,本質上就是封裝了 Feign
並提供了 SpringBoot
的支持,歡迎有相似需求的朋友下載使用。
feign-plus
源碼:https://github.com/crossoverJie/feign-plus
你的點贊與分享是對我最大的支持