事情是这样的,最近在代码中须要使用 Feign 调用第三方服务。因此就是标准的一套操做:java
@EnableFeignClients
注解注入 Bean。@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
在调试代码的时候出现一个奇怪的错误,引入的 Bean 竟然为空,这让我感到异常困惑,加上对 Spring 不是很熟悉,让我顿感不安。json
一顿百度、谷歌打断点调试,其中有个说的有道理api
EnableFeignClients
扫描路径与 ComponentScan
扫描冲突检查后配置后发现没有问题。数组
直到查看到代码中关于两个 Feign 的导入才发现到了端倪。安全
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
终于问题的缘由找到了项目中 FeignClient
与 EnableFeignClients
的版本不一致致使 Bean 注入失败。 @Autowired(required = false)
忽略了 Bean 的注入。最终致使NullPointerException
。bash
本觉得找到问题就能够解决了,可是面对第三方的 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 是 Netflix 开发的声明式、模板化的HTTP客户端, Feign 能够帮助咱们更快捷、优雅地调用 HTTP。
简单的说 Feign 经过将注解处理为模板化请求来工做。参数在输出以前直接应用于这些模板。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这二者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
具体的能够参考 stackoverflow 的讨论。
主要说明 EnableFeignClients
与 FeignClient
。
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。 |