☰
Feign 简介与使用入门,请求、响应压缩,日志记录
2026/9/30 6:33:11 网站建设 项目流程

Feign 声明式web服务客户端

spring-cloud-openfeign 官网:Spring Cloud OpenFeign

spring cloud 官方 2.1.x 文档:Spring Cloud OpenFeign

feign Github 开源地址:https://github.com/OpenFeign/feign。

1、Feign 是一个声明式 Web 服务客户端/http 客户端,它使编写 Web 服务客户端更加容易,要使用 Feign,请创建一个接口并对其进行注解。它具有可插拔的注解支持,包括外部注解和 JAX-RS 注解。Feign 还支持可插拔的编码器和解码器。

2、Spring Cloud 增加了对 Spring MVC 注解的支持,并支持使用 Spring Web 中默认使用的 HttpMessageConverters,Spring Cloud 集成了 Ribbon 和 Eureka,在使用 Feign 时提供一个负载均衡的 http 客户端。

3、虽然直接使用 org.springframework.web.client.RestTemplate 也可以实现微服务之间的 http 调用,但是 feign 作为一个独立的库,更具有优势,它使得调用远程微服务的 API 就如同调用自己本地的 API 一样。

使用步骤

How to Include Feign?按着官网文档介绍,使用 feign 很简单,分为如下几步:

1)服务请求/调用/消费方在 pom.xml 文件中导入 feign 依赖:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

2)服务请求/调用/消费方在启动类上加上 @org.springframework.cloud.openfeign.EnableFeignClients 注解开启 feignClient 客户端:

@SpringBootApplication @EnableFeignClients public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

3)服务请求/调用/消费方创建一个接口,@FeignClient 表示此接口为 feign 客户端,"stores" 为服务提供者的微服务名称,可以从注册中心看到,接口中的方法就是服务提供者 Cotroller 层的方法。其中 @RequestMapping 请求方式必须与服务提供者提供的方式一致,value 是请求路径,如果对方设置了应用上下文,则 value 中也要加上,方法名称可以自定义,不过建议与服务提供者一致。

@FeignClient(name = "${feign.name.stores-server:stores}") public interface StoreClient { @RequestMapping(method = RequestMethod.GET, value = "/stores") List<Store> getStores(); @RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json") Store update(@PathVariable("storeId") Long storeId, Store store); }

4)然后服务请求/调用/消费方可以在自己的 Controller 中调用上面接口中的方法,表面上好像调用自己的 API,实际上会通过微服务名称和路径调用远程微服务接口。官网文档:Spring Cloud OpenFeign

@FeignClient 注解说明

@FeignClient是 OpenFeign 的注解,作用:把接口变成远程 HTTP 调用客户端,像调用本地方法一样调用微服务接口。本质:动态代理,启动时生成接口实现类,方法调用 → 组装 http 请求 → 发请求 → 解析响应。

属性说明
name/value

微服务名称,用于服务发现;value和 name 完全等价。支持${}读取yml中的配置。

负载均衡:Feign 底层整合 Ribbon/Spring Cloud LoadBalancer,会根据 name 去注册中心拿服务实例列表做负载。

url

指定远程地址,直连,不走注册中心。例如url = "http://127.0.0.1:8080",支持${}读取配置。写了 url 就绕过服务发现,优先级更高,一般用于本地调试。

如果使用直连 url,则 name 可以随便填,但不能为空。

contextId

Feign 客户端 Bean 的 id,解决同名 name 冲突;推荐必写。

OpenFeign 除了生成接口代理 Bean,还会注册一个FeignClientSpecification,用来保存当前 Feign 客户端所有配置(超时、拦截器、配置类等),这个 Bean 才受 contextId 控制。

与 @Autowired、@Resource 注入的 Bean 不同。

加contextId,就是给FeignClientSpecification单独命名隔离,不改变接口代理 Bean 名字。

path统一接口前缀。远程服务所有接口都有前缀/api/acc,就写path="/api/acc",接口方法上的 @RequestMapping 就不用重复写前缀
primaryboolean,默认 true。多个相同类型 Bean 时,是否作为主 Bean,注入时优先选它。一般不用改
qualifier

Bean 限定符,和 @Qualifier 作用一样,用于注入区分。

qualifier 可以给代理 Bean起别名,用来配合@Qualifier按名称注入,这个才是修改代理 Bean 别名的属性,不是 contextId。

fallback熔断降级类。指定一个实现当前 Feign 接口的 class,调用异常 / 超时触发降级,返回兜底数据。需要开启 Hystrix/Sentinel 支持
fallbackFactory降级工厂。和 fallback 区别:工厂可以拿到异常信息,可以根据不同异常返回不同兜底结果,比 fallback 更灵活
configuration指定当前 Feign 客户端自定义配置类。可以单独为这个客户端配置:解码器、编码器、日志级别、超时时间、拦截器等。⚠️ 配置类不要加@Configuration,否则变成全局 Feign 配置

超时配置

feign: client: config: default: # 全局默认超时配置,所有feign都生效 connectTimeout: 10000 # 连接超时(ms) readTimeout: 600000 #读取超时(md) xxx: # 为指定Feign接口指定超时配置,有 contextId 配置时,优先写 contextId 的值,没有时,写name服务名(不是接口名) connectTimeout: 10000 readTimeout: 600000 loggerLevel: FULL # 单独开启详细日志,需求参考[日志记录章节]开启日志

注意事项 & 温馨提示

注意事项点示例

接口提供方接口方法参数比调用方定义的多,但是参数为非必传,调用方可以正常调用。

比如接口提供方后期新加了参数,但是接口调用方无法同步修改,此时定为非必传时,传与不传都可以兼容。

接口提供方接口方法参数比调用方定义的多,且参数为必传,提供方无法执行,会提示缺少参数,但是调用方也不会抛异常。

接口提供方接口方法参数比调用方定义的少,调用方可以正常调用。

比如接口提供方后期减少了参数,但是接口调用方无法同步修改,此时多传了不影响。

接口提供方还可以在任意位置获取对方传过来的查询参数:

RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
String formula_type = request.getParameter("xxx");

@RequestParam 必须写参数名,不能只写 `@RequestParam Integer type`(低版本会丢失参数名)
@RequestBody 只能用于 POST
不支持 @PathVariable 省略名称,必须 @PathVariable("id")
同一个微服务,多个 Feign 接口,不写 contextId → Bean 冲突启动报错
url和name同时存在:url 优先级更高,不走注册中心,直接访问指定地址
Feign 默认超时很短,高并发场景要在 yaml 配置 connectTimeout、readTimeout
传参容易丢:@RequestParam、@PathVariable 必须显式写参数名称

Feign 声明式web客户端使用

1、使用非常简单,开发环境为:Java JDK 1.8 + Spring Boot 2.1.3 + Spring Cloud Greenwich.SR1 + IDEA 2018。

2、准备三个微服务应用:eurekaserver_changsha 应用作 eureka 服务端,用于服务注册;eureka-client-food 应用提供服务;feign-client-cat 应用作为服务请求者,请求 eureka-client-food 提供的服务(接口)

3、操作流程:用户从浏览器访问 feign-client-cat 、feign-client-cat 应用内部调用 eureka-client-food 微服务,然后返回数据。

eurekaserver_changsha(注册中心)

1、pom.xml 文件核心内容如下(详细源码地址:GitHub - wangmaoxiong/feign_first: Feign 简介及基础使用):

... <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>

2、全局配置文件内容如下(详细源码地址:GitHub - wangmaoxiong/feign_first: Feign 简介及基础使用):

server: port: 9393 eureka: server: enable-self-preservation: false #关闭自我保护机制 eviction-interval-timer-in-ms: 60000 #驱逐计时器扫描失效服务间隔时间。(单位毫秒,默认 60*1000) instance: hostname: localhost client: register-with-eureka: false #禁用自己向自己注册 fetch-registry: false #不同步其他的 Eureka Server节点的数据 service-url: #Eureka Client 与 Eureka Server 交互的地址 default-zone: http://${eureka.instance.hostname}:${server.port}/eureka/

3、启动类上添加 @EnableEurekaServer:

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @EnableEurekaServer:开启 eureka 服务 */ @SpringBootApplication @EnableEurekaServer public class EurekaserverChangshaApplication { public static void main(String[] args) { SpringApplication.run(EurekaserverChangshaApplication.class, args); } }

注册中心提供服务注册,内容不多。

eureka-client-food(服务提供者)

1、pom.xml 文件核心内容如下(详细源码地址:GitHub - wangmaoxiong/feign_first: Feign 简介及基础使用):

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> ...

2、全局配置文件内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

server: port: 9395 #服务器端口 servlet: context-path: /food #应用访问上下文 spring: application: name: eureka-client-food #微服务名称 eureka: client: service-url: defaultZone: http://localhost:9393/eureka/ #eureka 服务器地址 instance: prefer-ip-address: true # IP 地址代替主机名注册 instance-id: changSha-food # 微服务实例id名称

3、服务提供者提供的服务就是 http 访问的接口,所以创建一个 Controller 层,提供访问接口,其中提供了不同参数的访问方式,以达到基本满足日常开发的需要:

feign_first/eurekaclient_food/src/main/java/wmx/com/eurekaclient_food/controller/Cuisine.java at master · wangmaoxiong/feign_first · GitHub.

feign-client-cat(服务消费者)

1、pom.xml 文件核心内容如下(详细源码地址:GitHub - wangmaoxiong/feign_first: Feign 简介及基础使用):

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> ... <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> ...

2、全局配置文件内容如下(详细源码地址:https://github.com/wangmaoxiong/feign_first):

server: port: 9394 #服务器端口 servlet: context-path: /cat #应用访问上下文 spring: application: name: feign-client-cat #微服务名称 eureka: client: service-url: defaultZone: http://localhost:9393/eureka/ #eureka 服务器地址 instance: prefer-ip-address: true # IP 地址代替主机名注册 instance-id: feign-cat # 微服务实例id名称 feign: name: food: eureka-client-food #服务提供方的服务名称,自定义配置。

3、启动类代码如下:

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @EnableFeignClients:开启 feign 客户端 * @EnableEurekaClient:开启 eureka 客户端,可以不写,默认就是开启的 */ @SpringBootApplication @EnableFeignClients @EnableEurekaClient public class FeignClientCatApplication { public static void main(String[] args) { SpringApplication.run(FeignClientCatApplication.class, args); } }

4、提供 feign 客户端接口如下:

1)@FeignClient 注解的 vaule 和 name 其实是一个属性,互相使用了别名,完全等价。值为服务提供方的服务名称。 2)@FeignClient(name = "${feign.name.food}"):推荐方式,服务提供方的服务名称从配置文件读取。

feign_first/feign_client_cat/src/main/java/wmx/com/feign_client_cat/feignClient/FoodFeignClient.java at master · wangmaoxiong/feign_first · GitHub.

5、@FeignClient 客户端接口中的方法请求方式要求与服务提供者一致,然而服务消费者自己控制层的调用方式是不受约束的,可以自己随意设置,控制层调用代码如下:

详细源码地址:feign_first/feign_client_cat/src/main/java/wmx/com/feign_client_cat/controller/CatController.java at master · wangmaoxiong/feign_first · GitHub.

浏览器访问微服务调用测试

1、顺序启动 eureka 注册中心、服务提供者、服务消费者,然后从浏览器请求 feign-client-cat,如果它能从 eureka-client-food(服务提供者)获取数据并返回,则说明成功。

2、因为有 post 请求,所以在 firefox 浏览器上安装使用 https://addons.mozilla.org/zh-CN/firefox/addon/restclient/ 插件进行访问测试:

Feign 请求与响应压缩 与 日志

Feign 请求与响应压缩

1、Feign request/response compression:可以为 feign 请求或响应 使用 gzip 压缩,压缩设置与为 web 服务器的设置类似,允许选择压缩媒体类型和最小请求阈值长度。哪边使用 feign 就配置在哪边。

feign.compression.request.enabled=true #开启 feign 请求压缩,默认 false feign.compression.response.enabled=true #开启 feign 响应压缩,默认 false feign.compression.request.mime-types=text/xml,application/xml,application/json #设置 feign 请求压缩类型 feign.compression.request.min-request-size=2048 #开启 feign 请求压缩阈值,超过此值才进行压缩,默认 2048

需要明确两点:一是Feign的请求压缩是我方(调用方)压缩请求体,发给对方;二是响应压缩是对方压缩响应体,返回给我方解压。

2、亲身经历过一次 feign 调用报错,服务 A 调用服务 B,debug 可以看到 B 的方法能正常进入,对方也没有报错,但是对方返回后,服务 A 这边直接报错如下,说是无法解析返回的内容,最后是服务A这边的 feign.compression.response.enabled 设置为 false 才得以解决。

2023-05-16 14:08:03 WARN [http-nio-7071-exec-9] o.s.cloud.tsf.route.util.TsfRouteInterceptUtil:114 tsf route, handle request tsf route rule , target service name is null, route not work. 2023-05-16 14:08:03 ERROR [http-nio-7071-exec-9] grp.aop.InterfaceRequestErrorAndPerformanceLog:91 ReturnData grp.basic3.busi.controller.BasExpCriController3.auditByData(String,String,List) 接口调用失败! 参数为:[003001, null, [{id=bbe12bb2-8c6d-446c-b524-7549ddd2a185, exp_cri_id=237484f1-f6d3-43e5-b5cd-e8b10305047e, exp_cri_code=Z01002, exp_cri_name=测试-24版本, exp_cri_class_id=596, exp_cri_class_code=3, exp_cri_class=暂定标准, exp_cri_class_name=暂定标准, exp_cri_class_codename=3 暂定标准, mof_div_code=210000000, fiscal_year=2024, unit=个, form_id=10576, form_code=1, form=定额, form_name=定额, form_codename=1 定额, exp_cri_val=60000, exp_eco_cls_id=null, exp_eco_cls_code=null, exp_eco_cls_name=null, exp_eco_cls_codename= , start_date=2023-05-16 11:36:56, end_date=2099-12-31 00:00:00, is_enabled=1, update_time=2023-05-16 11:36:56, is_deleted=2, create_time=2023-05-16 11:36:56, remark=, parent_id=0, is_leaf=1, level_no=1, create_user_id=211464028, create_user_code=21000000300111, create_user_name=鞠鑫, update_user_id=211464028, update_user_code=21000000300111, update_user_name=鞠鑫, exp_cri_busi_cate_id=dc4e5583-11e8-47a8-b9c6-7d3704fa1967, exp_cri_busi_cate_code=Z01, exp_cri_busi_cate_name=暂定标准, exp_cri_busi_cate_codename=Z01 暂定标准, audit_id=bbe12bb2-8c6d-446c-b524-7549ddd2a185, agency_id=12, is_end=2, create_menu_id=1c7b82de5f424c84b2f9c5eb53c8fcd8, ele_id=null, ele_code=null, ele_name=null, ele_codename= , bill_no=E003001-0, agency_code=003001, agency_name=中共辽宁省直属机关工作委员会本级, is_confirmed=2, mof_div_name=辽宁省本级, biz_key=237484f1-f6d3-43e5-b5cd-e8b10305047e, dep_bgt_eco_id=null, dep_bgt_eco_code=null, dep_bgt_eco_name=null, dep_bgt_eco_codename= , is_last_inst=2, rownum_=1, agency_codename=003001 中共辽宁省直属机关工作委员会本级}]] feign.codec.DecodeException: Error while extracting response for type [class grp.pt.core.ReturnData] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens; nested exception is com.fasterxml.jackson.core.JsonParseException: Illegal character ((CTRL-CHAR, code 31)): only regular white space (\r, \n, \t) is allowed between tokens at [Source: (PushbackInputStream); line: 1, column: 2] at feign.SynchronousMethodHandler.decode(SynchronousMethodHandler.java:174) ~[feign-core-9.7.0.jar!/:na] at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:134) ~[feign-core-9.7.0.jar!/:na] at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:77) ~[feign-core-9.7.0.jar!/:na] at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:102) ~[feign-core-9.7.0.jar!/:na] at com.sun.proxy.$Proxy238.updateIsenabled(Unknown Source) ~[na:na] at grp.bgt.pm.service.PmEstImateFeignService.updateIsenabled(PmEstImateFeignService.java:27) ~[bgt-com-3.2.0.jar!/:na] at grp.basic3.busi.service.AbstractBasExpCriService3.auditByData(AbstractBasExpCriService3.java:733) ~[classes!/:3.2.0(build20230418)_TSF] at grp.basic3.busi.service.AbstractBasExpCriService3$$FastClassBySpringCGLIB$$9b31790f.invoke(<generated>) ~[classes!/:3.2.0(build20230418)_TSF]

底层原理

feign.compression.request.enabled=true是我方(Feign客户端)压缩,然后发送给对方的。更准确地说:当你的服务(服务A)通过Feign客户端调用另一个服务(服务B)时,如果服务A配置了feign.compression.request.enabled=true,那么服务A会在发出请求之前,将自己要发送的请求体(比如一个大的JSON对象)进行压缩(默认使用GZIP),然后再发送给服务B。

  1. 请求发出前(在服务A - Feign客户端):

    • 你的应用程序通过Feign客户端接口准备发起一个远程调用。

    • Feign框架会检查当前配置:feign.compression.request.enabled是否为true。

    • 如果为true,它会进一步检查要发送的请求体(Body)内容类型(MIME type)是否匹配feign.compression.request.mime-types(如application/json)。

    • 同时,它会检查请求体的大小是否超过了feign.compression.request.min-request-size(默认2048字节,即2KB)。

    • 如果所有条件都满足,Feign会使用GZIP算法对你的请求体进行压缩。

    • 压缩完成后,Feign会自动在请求头(Request Headers)中添加一个字段:Content-Encoding: gzip。这个头是HTTP协议的标准部分,用来告诉接收方(服务B):“我这个请求的Body是用gzip压缩过的,你收到后需要先解压”。

  2. 请求接收时(在服务B - 被调用方):

    • 服务B(例如一个Spring Boot应用)通过它的HTTP服务器(如Tomcat)接收到这个请求。

    • HTTP服务器或Spring框架的底层机制会查看请求头中的Content-Encoding字段。

    • 如果发现其值为gzip,服务B有责任自动将这个压缩的请求体解压,还原成原始的JSON或其他格式的数据,然后再将解压后的数据交给你的Controller方法进行处理。

    • 因此,服务B的Controller代码完全感知不到压缩过程,它接收到的已经是解压后的完整对象,就像接收一个普通请求一样。

feign.compression.response.enabled=true:这个是对方压缩,我方解压。

  • 我方(Feign客户端)在请求头中会添加Accept-Encoding: gzip,告诉服务B:“我可以接受压缩后的响应,请你有压缩能力的话就压缩一下再发给我”。

  • 如果服务B支持并配置了压缩,它就会压缩响应体,并在它的响应头中加上Content-Encoding: gzip。

  • 我方Feign客户端收到响应后,看到Content-Encoding: gzip头,就会自动解压,然后再将解压后的内容交给Jackson进行JSON解析。

结论与建议

  1. feign.compression.request.enabled=true:是我方压缩请求体,目的是减少出站网络带宽的占用,适合调用时发送的请求体较大的场景。

  2. 要让整个流程正常工作,通信双方必须遵守HTTP协议关于Content-Encoding头的约定。

    • 压缩方(无论是请求的发送方还是响应的发送方)负责设置Content-Encoding: gzip。

    • 解压方(接收方)负责识别这个头并执行解压操作。

  3. 你最初遇到的“Illegal character (CTRL-CHAR, code 31)”错误,很可能是因为:

    • 我方Feign客户端配置了feign.compression.response.enabled=true,期望收到压缩响应。

    • 但对方服务返回了一个没有Content-Encoding: gzip头但却被压缩了的响应体(或者相反,返回了有gzip头但未压缩的响应体)。

    • 导致我方Feign客户端错误地尝试去解压一段原本未压缩的JSON数据,而GZIP文件的文件头恰好就包含ASCII码为31的字符,从而引发Jackson解析失败。

建议:如果不确定对方服务是否支持压缩或行为是否规范,最稳妥的做法是只开启请求压缩,关闭响应压缩(feign.compression.response.enabled=false),这样可以避免大多数奇怪的解析错误

Feign 日志记录

1、Feign logging:Feign 日志默认是不开启的,可以通过配置进行开启,如下所示,logging.level 表示日志级别,后面跟着 feign 客户端接口的完整类名,或者它的包名,日志记录只响应 debug 级别,所以值只能是 debug。

logging: level: wmx.com.feign_client_cat.feignClient.FoodFeignClient: debug

2、上面的配置开启之后表示 feign 可以记录日志了,但是具体怎么记录,还需要在配置类(@Configuration)中进行指定记录级别:

级别作用
NONE默认:不输出任何 Feign 日志(生产推荐)
BASIC仅记录请求方法、URL、响应状态码、耗时
HEADERSBASIC + 请求头、响应头
FULLHEADERS + 请求体、响应体(调试用,生产严禁,会打印敏感数据)

3、例下面将 logger.level 设置为 full 级别:

import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class SysConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }

4、当再次访问 feign-client-cat 微服务,它内部调用 eureka-client-food 时,控制台打印日志记录如下:

2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] <--- HTTP/1.1 200 (268ms) 2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] content-length: 89 2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] content-type: text/plain;charset=UTF-8 2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] date: Mon, 04 Nov 2019 09:35:36 GMT 2019-11-04 17:35:36.768 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] 2019-11-04 17:35:36.770 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] {"code":200,"message":"更新成功","uid":"889uuo65eud99","data":"name_zhangsan,age_33"} 2019-11-04 17:35:36.770 DEBUG 8912 --- [nio-9394-exec-1] w.c.f.feignClient.FoodFeignClient : [FoodFeignClient#updateData] <--- END HTTP (89-byte body)

动态 feign 接口调用

1、有时候需要根据配置的服务名称、Url、参数来远程调用,这样就没办法提前定义Feign接口,当然此时直接使用其他 Http 库调用也是可以的,比如 Apache HttpClient、RestTemplate、OkHttpClient 等等。

2、本文使用 FeignClientBuilder 也可以实现 Feign 动态接口调用。

package grp.basic3.dynamicfeign; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** *动态feign接口,调用示例: * dynamicFeignClient.executePostApi("bgt-basic-server","/seFeignBasPerson/genAssistPersonsYSBZ",new HashMap()); * dynamicFeignClient.executePostApi("bgt-basic-server","/debt/queryBasBondLoan",new ArrayList()); */ @Component public class DynamicFeignClient { @Autowired private DynamicFeignFactory<IDynamicFeignService> dynamicFeignFactory; /** * * @param feignName 如:基础库 bgt-basic-server * @param url 如:/aa/bb * @param params 如:具体参数 * @return */ public Object executePostApi(String feignName, String url, Object params) { IDynamicFeignService dynamicService = dynamicFeignFactory.getFeignClient(IDynamicFeignService.class, feignName); return dynamicService.executePostFeign(url, params); } } package grp.basic3.dynamicfeign; import org.springframework.cloud.openfeign.FeignClientBuilder; import org.springframework.context.ApplicationContext; import org.springframework.stereotype.Component; @Component public class DynamicFeignFactory<T> { private FeignClientBuilder feignClientBuilder; public DynamicFeignFactory(ApplicationContext appContext) { this.feignClientBuilder = new FeignClientBuilder(appContext); } public T getFeignClient(final Class<T> type, String serviceId) { return this.feignClientBuilder.forType(type, serviceId).build(); } } package grp.basic3.dynamicfeign; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; public interface IDynamicFeignService { @PostMapping("{url}") Object executePostFeign(@PathVariable("url") String url, @RequestBody Object params); }

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询