基于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<String> api(@Param("param") String param);

}

4.2 接口发布

@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 调用

@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 结果(很明显,是异步调用)

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

一切幻想破灭

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

到此这篇关于基于Feign实现异步调用的文章就介绍到这了,更多相关Feign异步调用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringCloud项目集成Feign、Hystrix过程解析

    这篇文章主要介绍了SpringCloud项目集成Feign.Hystrix过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Feign的功能:这是个消费者,根据服务注册在Eureka的ID去找到该服务,并调用接口 Hystrix的功能:熔断器,假如A服务需要调用B服务的/cities接口获取数据,那就在A服务的controller里声明@HystrixCommand,如果B服务的/cities接口挂了,就返回一个自定义的值 项目结构 [r

  • SpringCloud Open feign 使用okhttp 优化详解

    我就废话不多说了,大家还是直接看代码吧~ <!--web 模块 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <!--排除tomcat依赖 --> <exclusion> <artifactId&

  • SpringCloud Feign如何在远程调用中传输文件

    1. 文件远程传输主要涉及3点: 请求方式, 媒体类型, 序列化与反序列化, 把握住了这3点,基本上就可以搞 2. 使用Feign传输,首先搭建起Feign的架子 2.1 引入spring-cloud-starter-eureka-server依赖,用于启动一个eureka注册中心 2.2 引入spring-cloud-starter-eureka依赖,用于开启向eureka注册中心注册自己 2.3 在调用远程服务的客户端引入spring-cloud-starter-feign, 用于使用fei

  • Springcloud基于OpenFeign实现服务调用代码实例

    1.依赖 <!--引入open feign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> </dependencies> 2.启动注解 @SpringBootApplication @Enabl

  • SpringCloud OpenFeign Post请求400错误解决方案

    在微服务开发中SpringCloud全家桶集成了OpenFeign用于服务调用,SpringCloud的OpenFeign使用SpringMVCContract来解析OpenFeign的接口定义. 但是SpringMVCContract的Post接口解析实现有个巨坑,就是如果使用的是@RequestParam传参的Post请求,参数是直接挂在URL上的. 问题发现与分析 最近线上服务器突然经常性出现CPU高负载的预警,经过排查发现日志出来了大量的OpenFeign跨服务调用出现400的错误(HT

  • 基于springcloud异步线程池、高并发请求feign的解决方案

    ScenTaskTestApplication.java package com.test; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author scen *

  • SpringCloud Feign的使用代码实例

    1.官方文档 https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.2.RELEASE/reference/html/ 2.添加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dep

  • SpringCloud Feign的使用简介

    简介 feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service.Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端. 在springcloud中不仅可以使用Ribbo进行负载均衡,也可以使用Feign.Feign是在Ribbon的基础上进行了一次改进,采用接口的方式实现负载均衡. 使用 导入依赖 <dependency> <groupId>org.sprin

  • SpringCloud Feign转发请求头(防止session失效)的解决方案

    微服务开发中经常有这样的需求,公司自定义了通用的请求头,需要在微服务的调用链中转发,比如在请求头中加入了token,或者某个自定义的信息uniqueId,总之就是自定义的一个键值对的东东,A服务调用B服务,B服务调用C服务,这样通用的东西如何让他在一个调用链中不断地传递下去呢?以A服务为例: 方案1 最傻的办法,在程序中获取,调用B的时候再转发,怎么获取在Controller中国通过注解获取,或者通过request对象获取,这个不难,在请求B服务的时候,通过注解将值放进去即可:简代码如下: 获取

  • 详解springcloud 基于feign的服务接口的统一hystrix降级处理

    springcloud开发微服务时,基于feign来做声明式服务接口,当启用hystrix服务熔断降级时,项目服务众多,每个Feign服务接口都得写一些重复问的服务降级处理代码,势必显得枯燥无味: Feign服务接口: @FeignClient(name="springcloud-nacos-producer", qualifier="productApiService", contextId="productApiService", fallb

  • SpringCloud 服务负载均衡和调用 Ribbon、OpenFeign的方法

    1.Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的-套客户端―负载均衡的工具. 简单的说,Ribbon是Netlix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用.Ribbon客户端组件提供一系列完善的配置项如连接超时,重试等.简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器.我们很容易使用Ribbon实现自定义的负载均

  • 完美解决SpringCloud-OpenFeign使用okhttp替换不生效问题

    事发地 原默认的Feign是使用URLConnector进行通信的,当换为okhttp时,直接引入包及配置以下内容根本不生效,还是走原生的. feign: okhttp: enable: true 事件还原 创建项目并引入pom相关的依赖如下: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xml

  • 浅谈SpringCloud feign的http请求组件优化方案

    1 描述 如果我们直接使用SpringCloud Feign进行服务间调用的时候,http组件使用的是JDK的HttpURLConnection,每次请求都会新建一个连接,没有使用线程池复用.具体的可以从源码进行分析 2 源码分析 我们在分析源码很难找到入口,不知道从何开始入手,我们在分析SpringCloud feign的时候可用在配置文件下面我讲一下个人的思路. 1 首先我点击@EnableFeignClients 看一下这个注解在哪个资源路径下 如下图所示: 2 找到服务启动加载的配置文件

  • SpringCloud之Feign远程接口映射的实现

    一.简介 SpringCloud是基于Restful的远程调用框架,引入Ribbon负载均衡组件后还需要客户端使用RestTemplate调用远程接口,操作起来还显得繁琐.SpringCloud提供了远程接口映射,将远程Restful服务映射为远程接口,消费端注入远程接口即可实现方法调用. 二.流程 1.新建远程接口映射模块service-api,并引入Feign接口映射依赖 <dependencies> <dependency> <groupId>org.spring

  • SpringCloud Feign服务调用请求方式总结

    前言 最近做微服务架构的项目,在用feign来进行服务间的调用.在互调的过程中,难免出现问题,根据错误总结了一下,主要是请求方式的错误和接参数的错误造成的.在此进行一下总结记录.以下通过分为三种情况说明,无参数,单参数,多参数.每种情况再分get和post两种请求方式进行说明.这样的话,6种情况涵盖了feign调用的所有情况. 有个建议就是为了保证不必要的麻烦,在写feign接口的时候,与我们的映射方法保持绝对一致,同时请求方式,请求参数注解也都不偷懒的写上.如果遵循这种规范,可以避开90%的调

随机推荐