基于Feign实现异步调用

网友投稿 452 2022-10-24


基于Feign实现异步调用

一、背景

希望将http的调用由同步等待改为异步,仍使用feign的便捷。

二、使用feign理由

本质上其实feign就是将httpclient常用的操作进行简单封装,且屏蔽底层的httpclient,无感知具体的client实现,轻松完成具体client的替换

三、解决方案

feign在10.8版本后提供了Async接口,如下:

四、demo代码实现

4.1 接口编写

public interface OriginFeignClient {

    @RequestLine("POST /async/server/api")

    CompletableFuture api(@Param("param") String param);

}

4.2 接口发布

@Configuration

public class OriginFeignClientConfig {

@Bean

public SpringEncoder springEncoder(ObjectFTnudNactory messageConverters) {

return new SpringEncoder(messageConverters);

}

@Bean

public SpringDecoder springDecoder(ObjectFactory 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 调用

@GetMapping("testApi")

public String testAsyncClient() throws ExecutionException, InterruptedException {

List> results = new ArrayList<>();

for(int i = 0; i < 10; i++) {

results.add(originFeignClient.api(i+""));

}

Thread.sleep(3000);

int index = 0;

for (CompletableFuture result : results) {

String str = result.get();

log.info(String.format("%d, result:%s, ", index, str));

index++;

}

return "success";

}

4.4 结果(很明显,是异步调用)

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实现是10.8版本,我们找到Spring boot 2.2.13和相应cloud最新版Hoxton.SR11(当然不是最新,是该小版本下最新,因为目前项目中使用的就是该版本),排查思路就是以@EnableFeignClients为入口

1.EnableFeignClients内容如下

@Import(FeignClientsRegistrar.class)

public @interface EnableFeignClients {

}

引入了FeignClientsRegistrar

2.FeignClientsRegistrar功能如下:

(1)扫描@FeignClient,并将其下入到BeanDefinition中

(2)调用registerFeignClient,构造FeignClientFactoryBean(创建feign的工厂类,关键在此)

(3)进入FeignClientFactoryBean内部看下,构建feign的方法:getTarget():

从context中去找feign.Feign.Builder的实现(即@Bean),看下当前项目中有哪几种实现:

1.org.springframework.cloud.openfeign.FeignCircuitBreaker.Builder Spring Cloud定义的通用断路器

2.feign.hystrix.HystrixFeign.Builder 断路器的原生实现

先不管哪种builder,最终执行:loadBalance,方法内容如下:

protected T loadBalance(Feign.Builder builder, FeignContext context,

HardCodedTarget 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的创建,不对,等等!!Client,我们先看下他的实现类是不是包含我们的AsyncClient,

一切幻想破灭

好了,所以目前的Spring cloud openfeign中仍未支持该特性,先这样用吧


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Chrome 尝试安装.crx出现警告(加载已解压扩展程序)
下一篇:学习笔记之xss原理篇
相关文章

 发表评论

评论列表