记一次 Feign 的坑

事件回顾

原由

事情是这样的,最近在代码中须要使用 Feign 调用第三方服务。因此就是标准的一套操做:java

    1. 引入第三方服务 Jar 包。
    1. @EnableFeignClients 注解注入 Bean。
    1. @Autowired 引入 Bean。

而后也没有在乎到 Idea 已经有警告了,直接启动服务了。而后就出现以下错误:git

Description:

Field api in com.xxx.service.impl.ServiceImpl required a bean of type 'com.xxx.api.Api' 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.api.Api' in your configuration.
复制代码

PS: Idea 的告警为 Could not autowire. No beans of 'Api' type found.github

通过

而后结合 Idea 的警告与日志直接就配置 Autowired 的参数 @Autowired(required = false)算是暂时解决了项目能启动以及 Idea 的警告。web

可是。。。 可是。。。 可是。。。spring

image.png

在调试代码的时候出现一个奇怪的错误,引入的 Bean 竟然为空,这让我感到异常困惑,加上对 Spring 不是很熟悉,让我顿感不安。json

一顿百度、谷歌打断点调试,其中有个说的有道理api

  • EnableFeignClients 扫描路径与 ComponentScan 扫描冲突

检查后配置后发现没有问题。数组

直到查看到代码中关于两个 Feign 的导入才发现到了端倪。安全

  • import org.springframework.cloud.openfeign.EnableFeignClients;
  • import org.springframework.cloud.netflix.feign.FeignClient;

终于问题的缘由找到了项目中 FeignClientEnableFeignClients 的版本不一致致使 Bean 注入失败。 @Autowired(required = false) 忽略了 Bean 的注入。最终致使NullPointerExceptionbash

结果

本觉得找到问题就能够解决了,可是面对第三方的 Jar 包,显然直接修改代码是不可能的。

那替换本身的呢?

那也是不行的,由于第四方服务、第五方服务都是 openfeign 的注解。

思来想去最后只能在本身的项目中基于 openfeign 的实现与原业务相同的接口。其实就是复制代码更改注解,其余的啥也不是。代码大体以下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@FeignClient( name = "service", path = "/api/v1")
public interface ApiFeignClient {
    @RequestMapping( method = {RequestMethod.POST}, value = {"/query"}, consumes = {"application/json"} )
    ResponseBody query(@RequestBody RequestDto reqDto);

    @RequestMapping( method = {RequestMethod.GET}, value = {"/list"}, consumes = {"application/json"} )
    ResponseBody list(@RequestParam("name") String name);
}
复制代码

而后代码中使用咱们本身的 Bean,相似下面:

@Autowired
private ApiFeignClient api;
复制代码

这样有缺点就是第三方服务的逻辑更改并不能同步到你的服务。因此这是一种后知后觉的方法去解决问题。本质上仍是须要第三方服务实现基于 openfeign 的 Jar 包。

Feign 总结

通过这事以后,也查了不少资料,看了不少博客。这里总结一下关于 Feign 的知识点。

Feign 是什么?

Feign 是 Netflix 开发的声明式、模板化的HTTP客户端, Feign 能够帮助咱们更快捷、优雅地调用 HTTP。

简单的说 Feign 经过将注解处理为模板化请求来工做。参数在输出以前直接应用于这些模板。

Netflixfeign 与 Openfeign 区别

Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这二者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。

具体的能够参考 stackoverflow 的讨论。

注解的参数

主要说明 EnableFeignClientsFeignClient

  • EnableFeignClients 注解参数
名称 解释
value 为 basePackages 属性的别名,容许使用更简洁的书写方式。
basePackages 设置自动扫描带有 @FeignClient 注解的基础包路径。
basePackageClasses basePackages 属性的安全替代属性。扫描 @FeignClient修饰的类。
defaultConfiguration 该属性用来自定义全部Feign客户端的配置,使用 @Configuration进行配置。
clients 设置由 @FeignClient 注解修饰的类列表。注意 clients 不是空数组,则不经过类路径自动扫描功能来加载 FeignClient。
  • FeignClient 注解参数
名称 解释
name、value、serviceId 三者做用基本一致。name指定 FeignClient 的名称,若是项目使用了 Ribbon,name属性会做为微服务的名称,用于服务发现。serviceId 已经废弃.
qualifier 指定别名接本没用过。对应的是 @Qualifier注解
url 指定 FeignClient 调用的地址,通常用于调试程序。
decode404 调用出现 http404 错误且该字段位为true,会调用decoder进行解码,不然抛出异常
configuration Feign配置类,能够自定义Feign的 Encoder、Decoder、LogLevel、Contract。
fallback 定义容错的处理类,当调用远程接口异常时,会调用对应接口的异常逻辑,注意 fallback 指定的类必须实现 @FeignClient 标记的接口
fallbackFactory 用于生成fallback类示例,实现每一个接口通用的容错逻辑,减小重复的代码。
path 定义当前 FeignClient 的统一前缀。
primary 是否将伪代理标记为主 Bean,默认为true。

参考资料

相关文章
相关标签/搜索