返回顶部
首页 > 资讯 > 精选 >注解FeignClient使用的规范有哪些
  • 355
分享到

注解FeignClient使用的规范有哪些

2023-06-29 10:06:56 355人浏览 薄情痞子
摘要

本文小编为大家详细介绍“注解FeignClient使用的规范有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“注解FeignClient使用的规范有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。注解Fei

本文小编为大家详细介绍“注解FeignClient使用的规范有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“注解FeignClient使用的规范有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

注解FeignClient使用规范

首先是对FeignClient里的常用属性

  • contextId:当有多个服务调用方法不想写在一个接口里,就要使用到

  • name:指定FeignClient的名称,如果项目使用了Ribbon,name属性会作为微服务的名称,用于服务发现

  • url:url一般用于调试,可以手动指定@FeignClient调用的地址

  • fallback:定义容错的处理类,当调用远程接口失败或超时时,会调用对应接口的容错逻辑,fallback指定的类必须实现@FeignClient标记的接口

  • fallbackFactory:工厂类,用于生成fallback类示例,通过这个属性我们可以实现每个接口通用的容错逻辑,减少重复的代码 

  • path:定义当前FeignClient的统一前缀

使用FeignClient的原因

无非让一个微服务的接口被另一个服务访问,微服务的一个特点就是业务隔离,那就要尽量的做到数据库隔离,虽 然不是真的隔离,但是要尽量在代码上做隔离。

举例,系统有一个file-server,是系统的公共服务,附件的下载,上传,获取内容等接口实现。对应操作的表是系统附件表。

现在客户的信息里有附,正常是在客户与附件之间做连表查询,将附件信息拿到,但是在微服务里这样子做是不合规的。现在如果进行如下的引用

在controller类里定义的接口方法

//在controller类里定义的接口方法   @RequestMapping(value = "/add" ,method = RequestMethod.GET)public Integer add(@RequestParam Integer a, @RequestParam Integer b) { ServiceInstance instance = client.getLocalServiceInstance(); Integer r = a + b; logger.info("/add, host:" + instance.getHost() + ", service_id:" + instance.getServiceId() + ", result:" + r); return r;}

使用@FeignClient

@FeignClient("compute-service")public interface ComputeClient {    @RequestMapping(method = RequestMethod.GET, value = "/add")    Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);}

然后在另一个微服务里的controller层调用

@AutowiredComputeClient computeClient;@RequestMapping(value = "/add", method = RequestMethod.GET)public Integer add() {    return computeClient.add(10, 20);}

只能说使用成功了,但是不规范,这是网上随处可见的错误规范,一开始我也是错误的在controll层引用,但是被技术经理叼了,反正就是不合规。

理由很简单,给前端的接口不要重复。如果你这边controller调用原来的服务,不管是哪个微服务的,前端是可以直接访问的,那这样子的意义何在。接口给你调用,是让你用来获取有用的信息来处理,然后返回给前端。

所以应该在server层调用。

规范的使用@FignClient注解

以公共服务中的文件服务和客户业务模块进行服务间的通信为例

在文件服务的api模块里写如下

FeignClient(contextId = "fileService", value = ServicellaneConstants.FTLE_SERNVTCE,fallbackFactory=RenoteFileFallbackFactory.class)public interface RemoteFileservice {@PostMapping(value = "/upload",consumes = MediaType.WULTIPART_FORN_DATA_VALUE)public RcLong uplocad(CRequestParan("module ) String nodole ,ORequestParan("sunceId ) String souneId, OlequestFart(value = "file ") liltigartFile file);

此时在客户业务板块,即客户需要和附件进行相关信息的1对多查询,不能连表查询,那就调用上面的RemoteFileservice ,一开始我在客户模块里写了一个FileController,然后写接口,接口里调用,直接NO。

应该在业务层里调用就好了,用注解@Autowired,将你需要处理的数据获取到并处理好。

接下来看看fallbackFactory,主要是为降级处理就是出错了应该返回什么。

代码仅供参考,可能还会有其它 的写法

//注意FallbackFactory<你注解对应的接口类名>@componentpublic class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileService>private static final Logger log = LoggerFactory.getLogger(RemoteFileFallbackFactory.class);0verridepublic RemoteFileservice create(Throwable throwable){//打印出错日志log.error("文件朋务调用失败:{}", throwable.getHessage());return new RemoteFileserviceo{Overridepublic R<Long> upload(String module,String sourceId,MultipartFile file){return R.fail("上传失败:" + throwable.getMessage(o);}0verridepublic byte[ ] getFileBytes(Long fileId) { return new byte[0];}@0verridepublic R getURL(Long[] ids) { return R.fail("获取文件URL失败:" + throwable.getHessage());}@0verridepublic R<List<SysFileApivo>> getURL(List<Long> ids) {return R.fail("获取文件URL失败:" + throwable.getMessage());}};

想要怎么用,就动手实践吧

@FeignClient注解使用的常见问题

Feign 是一个声明式的 WEB 服务,通过定义一个添加相应注解的接口,即可完成一个 Web 服务的接口。SpringCloud 对 Feign 进行了封装以后,其开始能够支持 spring mvc 标准注解,同时在 SprinGCloud 架构上结合 Eureka 和 Ribbon,还能够支持负载均衡

既然是一个 Web 服务,必然服务端模块与客户端模块都加入 Feign 依赖以及对接的 api 接口,这是 Feign 服务的基本前提。因此双方引入的 Feign 接口都要保持一致,包括服务地址、入参定义、返回值等。

基本配置

要启用 @FeignClient 接口,首先需要引入 Feign 依赖:

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

在父 pom.xml 里还需要引入 SpringCloud 依赖,这样使用 FeignClient 才有意义。

在启动类上添加启动注解 @EnableFeignClients:

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.feign.EnableFeignClients; @SpringBootApplication@EnableFeignClientspublic class FeignDemoApp {    public static void main(String[] args) {        SpringApplication.run(FeignDemoApp.class, args);    }}

然后定义 Feign 客户端提供的服务接口,示例代码如下:

import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestBody;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod; import com.demo.feign.model.request.FeignDemoDetailRequest;import com.demo.feign.model.response.FeignDemoDetailResponse;import com.demo.feign.model.response.FeignDemoListResponse;@FeignClient("spring-boot-feign-demo")public interface FeignDemoClient {     @RequestMapping(value="/demo/list", method=RequestMethod.GET)    public FeignDemoListResponse queryListByCode(@PathVariable("code") String code);         @RequestMapping(value="/demo/detail", method=RequestMethod.POST)    public FeignDemoDetailResponse queryDetail(@RequestBody FeignDemoDetailRequest request);}

这里定义的 FeignDemoDetailRequest,FeignDemoDetailResponse 和 FeignDemoListResponse 是定义的实体类,具体就不展示了。

常见问题

Feign 的 Maven 依赖报红,或者主启动类上@EnableFeignClients不识别,一直报红,或者 feign 接口注入到控制器报红。

可能的原因及处理方案:

  • maven 包没有成功导入,或者 maven 包下载不完整,可以从仓库删掉依赖包后重新下载导入;

  • 版本冲突,或者无法获取适当版本,此时可以在 maven 包导入时指定版本号,尝试其他可用的版本。

项目 Application 启动时,使用 @Autowired 自动注入的 FeignClient 接口被告知对应的 Bean 无法寻获

***************************
APPLICATION FAILED TO START
***************************
 
Description:
Field feignDemoClient in com.xxx.xxx.service.impl.DemoServiceImpl required a bean of type 'com.xxx.xxx.feign.FeignDemoClient' that could not be found.
The injection point has the following annotations:
    - @org.springframework.beans.factory.annotation.Autowired(required=true)
 
Action:
Consider defining a bean of type 'com.xxx.xxx.feign.FeignDemoClient' in your configuration.
Disconnected from the target VM, address: '127.0.0.1:51645', transport: 'Socket'
Process finished with exit code 1

可能的原因及处理方案:

  • 服务所在模块没有在 pom.xml 引入 spring-cloud-starter-openfeign 这个 maven 依赖,补上这个依赖重新构建项目即可。

  • 项目启动没有扫描 FeignClient 接口所在的包。项目通过启动类启动时默认会扫描同目录及同目录下级目录的类文件。所以,Spring注入第三方包或者其他模块的包,需要扫描需要注入的包。这种情况,只需要在启动类的注解中指定需要扫描的包路径即可,如:

// 开启Feign客户端,指定扫描 FeignClient 接口类所在的包@EnableFeignClients("com.xxx.xxx.feign")@SpringBootApplication

正确添加 Feign 依赖,启动类扫描 api 接口所有包路径,但注入接口仍然报红

这种情况现在比较少见,但是在一段时间以前出现比较频繁,主要是在 SpringBoot 2.0 版本后优化了相关逻辑。在 SpringBoot 2.0 之前,如果你的 Feign 接口使用 GetMapping 注解,那么注入该接口都会报红,无法注入。相应的,修改成 RequestMapping 或者 PostMapping 就能注入了。

处理方案:

采用合适的注解形式定义 Feign 接口。目前可行的定义方式基本有以下几种:

@FeignClient("spring-boot-feign-demo")public interface FeignDemoClient {        // 使用RequestMapping指定Get方法,入参单个传入    @RequestMapping(value="/demo/list", method=RequestMethod.GET)    public FeignDemoListResponse queryListByCode(@PathVariable("code") String code);         // 使用RequestMapping指定Post方法,传入实体使用注解@RequestBody    @RequestMapping(value="/demo/detail", method=RequestMethod.POST)    public FeignDemoDetailResponse queryDetail(@RequestBody FeignDemoDetailRequest request);        // 使用PostMapping,传入实体使用注解@RequestBody    @PostMapping("/demo/seq")    public FeignDemoSeqResponse querySeq(@RequestBody FeignDemoSeqRequest request);}

通过 FeignClient 发起 Get 请求报 405 错误

通过在服务端断点捕获异常可以发现,报 405 错误的直接原因,其实是因为定义为 Get 的 Feign 接口,接收到 Post 方法的调用。但是在调用方调用时大多数也是采用 Get 方法,那么到底是什么原因呢?

暂且预设 Feign 接口的定义如下:

@FeignClient("spring-boot-feign-demo")public interface FeignDemoClient {    // 服务方接收到的请求是Post方法,而不是Get方法    @GetMapping(value="/demo/list")    public Response queryList(Request request);

实际上,通过断点跟踪接口调用时的调用路径,就会发现 FeignClient 最后是通过 HttpURLConnection 发起的网络连接,在发起的过程中,Connection 会判断自身请求的 body 是否为空。如果 body 不为空,则将 Get 方法转换成 Post 方法。因为 body 形式的数据只能方法 RequestBody 内以流的形式进行传输,而根据 Http 协议 param 形式的数据可以直接放在 URL 上进行传输和获取。

之所以 FeignClient 在网络请求时会出现这种转换,这跟它的初始化规则有关。在项目启动过程中,@FeignClient 直接的类会被初始化一个动态代理的类,并通过一个 RequestTemplate.Factory 的工厂类生成请求模板,具体规则如下:

  • 如果基本类型参数有 @RequestParam 注解,则会将参数作为 key 放入 RequestTemplate.Factory 中,通过 urlIndex 记录数组索引。在进行解析时,通过 key 从数组中获取具体的参数值,拼接在 url 后面。

  • 如果参数没有任何注解,或者有 @RequestBody 注解,那么初始化时会使用 bodyIndex 维护参数索引,并通过 bodyType 记录参数的具体类型。

需要注意的是,@RequestParam 只能用于对单个基本类型参数的注解,不能用来注解一个实体类。使用实体类作为入参出参时,建议还是使用 Post 方法进行请求。

如果在开发中觉得维护以上的对应关系不方便的话,还有另外一种修改方法可供使用,基本原理就是使用 Apache 的 HTTP Client 替换 Feign 原生的 Http Client,替换后 Get 方法也可以用一个实体类作为请求参数而不用担心请求被转换成 Post 方法了。具体修改方式如下:

引入 http client 依赖

<dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId><br>        <version>4.5.2</version></dependency><dependency>    <groupId>com.netflix.feign</groupId>    <artifactId>feign-httpclient</artifactId>    <version>8.18.0</version></dependency>

开启 Feign 对 httpClient 的设置

feign.httpclient.enabled=true

完成配置修改后,内部就可以使用 Apache 的 http client。Feign 接口的定义是相同的,但是由于 Get 方法支持了自定义实体类,与 Post 有类似的处理方式,因此参数的传输需要我们额外指定其类型,以确保 JSON 序列化与反序列化的正常进行。

这里给出一个示例接口定义:

@FeignClient("spring-boot-feign-demo")public interface FeignDemoClient {    @PostMapping(value="/demo/detail", consumes = MediaType.APPLICATION_jsON_VALUE)    public Response<List<ResultDTO>> query(@RequestBody FeignQueryRequest request,                                            @PathVariable("page") Integer page,                                            @PathVariable("page_size") Integer pageSize);}

JSON 反序列化失败

Error while extracting response for type [com.xxx.xxx.feign] and content type [application/json].Can not deserialize instance of java.util.ArrayList out of START_OBJECT token

翻译过来的意思大致就是,Feign 接口的返回值无法通过 application/json 的格式解析出来,也就是调用方返回值的定义就服务方不一致(结构不同)。

处理方案:

确保双方引入的接口 api 完全一致,可通过将接口所在模块打包成 jar 包,双方引用同一个 jar 等方式以保证接口定义一致。

读到这里,这篇“注解FeignClient使用的规范有哪些”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网精选频道。

--结束END--

本文标题: 注解FeignClient使用的规范有哪些

本文链接: https://lsjlt.com/news/324197.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 注解FeignClient使用的规范有哪些
    本文小编为大家详细介绍“注解FeignClient使用的规范有哪些”,内容详细,步骤清晰,细节处理妥当,希望这篇“注解FeignClient使用的规范有哪些”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。注解Fei...
    99+
    2023-06-29
  • 关于注解FeignClient的使用规范
    注解FeignClient使用规范 首先是对FeignClient里的常用属性 contextId:当有多个服务调用方法不想写在一个接口里,就要使用到name:指定FeignClie...
    99+
    2024-04-02
  • MySQL使用规范有哪些
    本篇内容介绍了“MySQL使用规范有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!数据库环境dev: ...
    99+
    2024-04-02
  • Git 使用规范有哪些
    本篇文章为大家展示了Git 使用规范有哪些,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。第一步:新建分支首先,每次开发新功能,都应该新建一个单独的分支(这方面可以参考《Git分支管理策略》)。# 获...
    99+
    2023-06-04
  • States字段使用规范有哪些
    States字段使用规范有哪些,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。解决方式States对应位域枚举StatesFla...
    99+
    2024-04-02
  • Java中代码注释的规范有哪些
    Java中代码注释的规范有哪些?很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。代码注释是架起程序设计者与程序阅读者之间的通信桥梁,最大限度的提高团队开发合作效率。...
    99+
    2023-05-31
    java 代码注释 ava
  • CSS中hack和注释规范有哪些
    这篇文章给大家介绍CSS中hack和注释规范有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。CSS中hack和注释书写规范一.hack书写规范因为不同浏览器对W3C标准的支持不一样...
    99+
    2024-04-02
  • 域名注册备案有哪些规范
    域名注册备案有哪些规范,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、 每个经营性网站只能申请一个网站名称;二、 经营性网站备案名称以通信管理部门批准文件核准为主要依据;三、...
    99+
    2023-06-07
  • sql规范有哪些
    这篇文章主要为大家展示了“sql规范有哪些”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“sql规范有哪些”这篇文章吧。看到itpub的微信发的,搬运一下,应该不...
    99+
    2024-04-02
  • CSS有哪些规范
    这篇文章主要介绍“CSS有哪些规范”,在日常操作中,相信很多人在CSS有哪些规范问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CSS有哪些规范”的疑惑有所帮助!接下来,请跟着...
    99+
    2024-04-02
  • HTML规范有哪些
    本篇内容主要讲解“HTML规范有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“HTML规范有哪些”吧!HTML 规范缩进统一两个空格缩进命名规范class ...
    99+
    2024-04-02
  • Redis规范有哪些
    这篇“Redis规范有哪些”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Redis规范有哪些”文章吧。redis 功能强大,...
    99+
    2023-06-27
  • codereview规范有哪些
    Code Review的规范可以有很多,这里列举一些常见的规范: 代码风格一致性:确保代码使用统一的缩进风格、命名规范、空格使用、...
    99+
    2023-10-21
    codereview
  • Ruby标识名使用规范有哪些
    这篇文章给大家介绍Ruby标识名使用规范有哪些,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。Ruby 的标识名用来指向常量,变量,方法,类和模块。标识名的首字母用来帮助我们确定标识所指向内容的作用域。Ruby标识名区分...
    99+
    2023-06-17
  • go语言的注释编码规范有哪些
    这篇文章主要介绍“go语言的注释编码规范有哪些”,在日常操作中,相信很多人在go语言的注释编码规范有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”go语言的注释编码规范有哪些”的疑惑有所帮助!接下来,请跟...
    99+
    2023-07-04
  • @Valid注解怎么规范使用
    这篇文章主要介绍“@Valid注解怎么规范使用”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“@Valid注解怎么规范使用”文章能帮助大家解决问题。@Valid注解大全及用法规范注解描述@Assert...
    99+
    2023-06-29
  • git commit规范的有哪些
    本篇内容介绍了“git commit规范的有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么要规范...
    99+
    2024-04-02
  • HTTP中有哪些规范
    这篇文章给大家介绍HTTP中有哪些规范,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。1.RefererHTTP 标准把 Referrer 写成 Referer(少些了一个 r),可以说...
    99+
    2024-04-02
  • Redis的开发规范有哪些
    本篇内容主要讲解“Redis的开发规范有哪些”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Redis的开发规范有哪些”吧!一、键值设计1、key名设计可读性和可...
    99+
    2024-04-02
  • JavaScript的编码规范有哪些
    本篇文章给大家分享的是有关JavaScript的编码规范有哪些,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。JavaScript 文件引用Ja...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作