基于Feign實現(xiàn)異步調(diào)用
一、背景
希望將http的調(diào)用由同步等待改為異步,仍使用feign的便捷。
二、使用feign理由
本質(zhì)上其實feign就是將httpclient常用的操作進行簡單封裝,且屏蔽底層的httpclient,無感知具體的client實現(xiàn),輕松完成具體client的替換
三、解決方案
feign在10.8版本后提供了Async接口,如下:
四、demo代碼實現(xiàn)
4.1 接口編寫
public interface OriginFeignClient { @RequestLine("POST /async/server/api") CompletableFuture<String> api(@Param("param") String param); }
4.2 接口發(fā)布
@Configuration public class OriginFeignClientConfig { @Bean public SpringEncoder springEncoder(ObjectFactory<HttpMessageConverters> messageConverters) { return new SpringEncoder(messageConverters); } @Bean public SpringDecoder springDecoder(ObjectFactory<HttpMessageConverters> messageConverters) { return new SpringDecoder(messageConverters); } @Bean public OriginFeignClient originFeignClient(SpringEncoder springEncoder, SpringDecoder springDecoder) { return AsyncFeign.asyncBuilder() .encoder(springEncoder) .decoder(springDecoder) .target(OriginFeignClient.class, "http://localhost.charlesproxy.com:8090"); } }
4.3 調(diào)用
@GetMapping("testApi") public String testAsyncClient() throws ExecutionException, InterruptedException { List<CompletableFuture<String>> results = new ArrayList<>(); for(int i = 0; i < 10; i++) { results.add(originFeignClient.api(i+"")); } Thread.sleep(3000); int index = 0; for (CompletableFuture<String> result : results) { String str = result.get(); log.info(String.format("%d, result:%s, ", index, str)); index++; } return "success"; }
4.4 結(jié)果(很明顯,是異步調(diào)用)
2021-05-11 14:31:29.989 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 0, result:receive: {"param":"0"} at 2021-05-11 02:31:27.243,
2021-05-11 14:31:29.993 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 1, result:receive: {"param":"1"} at 2021-05-11 02:31:27.243,
2021-05-11 14:31:29.995 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 2, result:receive: {"param":"2"} at 2021-05-11 02:31:27.244,
2021-05-11 14:31:29.995 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 3, result:receive: {"param":"3"} at 2021-05-11 02:31:27.245,
2021-05-11 14:31:29.995 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 4, result:receive: {"param":"4"} at 2021-05-11 02:31:27.243,
2021-05-11 14:31:29.996 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 5, result:receive: {"param":"5"} at 2021-05-11 02:31:27.243,
2021-05-11 14:31:29.996 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 6, result:receive: {"param":"6"} at 2021-05-11 02:31:27.244,
2021-05-11 14:31:29.997 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 7, result:receive: {"param":"7"} at 2021-05-11 02:31:27.243,
2021-05-11 14:31:29.997 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 8, result:receive: {"param":"8"} at 2021-05-11 02:31:27.244,
2021-05-11 14:31:29.998 - INFO [TraceId: , SpanId : ] 24745 --- [nio-8091-exec-5] c.m.a.c.controller.ClientController : 9, result:receive: {"param":"9"} at 2021-05-11 02:31:27.245,
五、問題
feign增加的async實現(xiàn)是10.8版本,我們找到Spring boot 2.2.13和相應(yīng)cloud最新版Hoxton.SR11(當(dāng)然不是最新,是該小版本下最新,因為目前項目中使用的就是該版本),排查思路就是以@EnableFeignClients為入口
1.EnableFeignClients內(nèi)容如下
@Import(FeignClientsRegistrar.class) public @interface EnableFeignClients { }
引入了FeignClientsRegistrar
2.FeignClientsRegistrar功能如下:
(1)掃描@FeignClient,并將其下入到BeanDefinition中
(2)調(diào)用registerFeignClient,構(gòu)造FeignClientFactoryBean(創(chuàng)建feign的工廠類,關(guān)鍵在此)
(3)進入FeignClientFactoryBean內(nèi)部看下,構(gòu)建feign的方法:getTarget():
從context中去找feign.Feign.Builder的實現(xiàn)(即@Bean),看下當(dāng)前項目中有哪幾種實現(xiàn):
1.org.springframework.cloud.openfeign.FeignCircuitBreaker.Builder Spring Cloud定義的通用斷路器
2.feign.hystrix.HystrixFeign.Builder 斷路器的原生實現(xiàn)
先不管哪種builder,最終執(zhí)行:loadBalance,方法內(nèi)容如下:
protected <T> T loadBalance(Feign.Builder builder, FeignContext context, HardCodedTarget<T> target) { Client client = getOptional(context, Client.class); if (client != null) { builder.client(client); Targeter targeter = get(context, Targeter.class); return targeter.target(this, builder, context, target); } throw new IllegalStateException( "No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-netflix-ribbon?"); }
好了?。】吹轿覀兿胍牧?,Client的創(chuàng)建,不對,等等??!Client,我們先看下他的實現(xiàn)類是不是包含我們的AsyncClient,
一切幻想破滅
好了,所以目前的Spring cloud openfeign中仍未支持該特性,先這樣用吧
到此這篇關(guān)于基于Feign實現(xiàn)異步調(diào)用的文章就介紹到這了,更多相關(guān)Feign異步調(diào)用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Hibernate的Session_flush與隔離級別代碼詳解
這篇文章主要介紹了Hibernate的Session_flush與隔離級別代碼詳解,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下2018-02-02微服務(wù)中使用Maven BOM來管理你的版本依賴詳解
這篇文章主要介紹了微服務(wù)中使用Maven BOM來管理你的版本依賴,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12淺談Java數(shù)值類型的轉(zhuǎn)換與強制轉(zhuǎn)換
這篇文章主要介紹了Java數(shù)值類型的轉(zhuǎn)換與強制轉(zhuǎn)換,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04java實現(xiàn)的連接數(shù)據(jù)庫及模糊查詢功能示例
這篇文章主要介紹了java實現(xiàn)的連接數(shù)據(jù)庫及模糊查詢功能,結(jié)合實例形式分析了java基于jdbc連接數(shù)據(jù)庫及使用LIKE語句實現(xiàn)模糊查詢功能的相關(guān)操作技巧,需要的朋友可以參考下2017-12-12Java算法之時間復(fù)雜度和空間復(fù)雜度的概念和計算
這篇文章主要介紹了Java算法之時間復(fù)雜度和空間復(fù)雜度的概念和計算,文中有非常詳細的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-05-05Java 是如何利用接口避免函數(shù)回調(diào)的方法
本篇文章主要介紹了Java 是如何利用接口避免函數(shù)回調(diào)的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-02-02