一.Feign是什么
Feign 的英文表意为“假装,伪装,变形”, 是一个http请求调用的轻量级框架,可以以Java接口注解的方式调用Http请求,而不用像Java中通过封装HTTP请求报文的方式直接调用。
Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
Feign是一个声明式的Web服务客户端,使用Feign可使得Web服务客户端的写入更加方便。 它的使用方法是定义一个接口,然后在上面添加注解,同时也支持JAX-RS标准的注解。
Spring Cloud集成了Ribbon和Eureka,在使用Feign时提供负载平衡的http客户端。
Feign也支持可拔插式的编码器和解码器,Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
Spring Cloud 增加了对 Spring MVC的注解,Spring Web 默认使用了HttpMessageConverters, Spring Cloud 集成 Ribbon 和 Eureka 提供的负载均衡的HTTP客户端 Feign.
Feign是spring cloud中服务消费端的调用框架,通常与ribbon,hystrix等组合使用。
但是在某些项目中,由于遗留原因,整个系统并不是spring cloud项目,甚至不是spring项目,而使用者关注的重点仅仅是简化http调用代码的编写。
Feign是从Netflix中分离出来的轻量级项目,能够在类接口上添加注释,成为一个REST API 客户端。
Feign中对 Hystrix 有依赖关系。Feign只是一个便利的rest框架,简化调用,最后还是通过ribbon在注册服务器中找到服务实例,然后对请求进行分配。
二.Feign能做什么
通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。
Feign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。
而Feign则会完全代理HTTP请求,只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix,可以让不再需要显式地使用这两个组件。
总起来说,Feign具有如下特性:
(1)可插拔的注解支持,包括Feign注解和JAX-RS注解;
(2)支持可插拔的HTTP编码器和解码器;
(3)支持Hystrix和它的Fallback;
(4)支持Ribbon的负载均衡;
(5)支持HTTP请求和响应的压缩。
这看起来有点像我们springmvc模式的Controller层的RequestMapping映射。Feign是用@FeignClient来映射服务的。
三.Feign原理
在Spring Cloud中,使用Feign非常简单——创建一个接口,并在接口上添加一些注解,代码就完成了。Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。
Spring Cloud对Feign进行了增强,使Feign支持了Spring MVC注解,并整合了Ribbon和Eureka,从而让Feign的使用更加方便。
Spring Cloud Feign是基于Netflix feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供这两者的强大功能外,还提供了一种声明式的Web服务客户端定义的方式。
Spring Cloud Feign帮助我们定义和实现依赖服务接口的定义。在Spring Cloud feign的实现下,只需要创建一个接口并用注解方式配置它,即可完成服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。
Spring Cloud Feign具备可插拔的注解支持,支持Feign注解、JAX-RS注解和Spring MVC的注解。
Feign封装了Http调用流程,更适合面向接口化的变成习惯。
在服务调用的场景中,经常调用基于Http协议的服务,而使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty等等,这些框架在基于自身的专注点提供了自身特性。
而从角色划分上来看,他们的职能是一致的提供Http调用服务。
具体流程如下:
Feign的设计的:
1、基于面向接口的动态代理方式生成实现类
在使用feign 时,会定义对应的接口类,在接口类上使用Http相关的注解,标识HTTP请求参数信息,如下所示:
interface GitHub { @RequestLine("GET /repos/{owner}/{repo}/contributors") List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo); } public static class Contributor { String login; int contributions; } public class MyApp { public static void main(String... args) { GitHub github = Feign.builder() .decoder(new GsonDecoder()) .target(GitHub.class, "https://api.github.com"); // Fetch and print a list of the contributors to this library. List<Contributor> contributors = github.contributors("OpenFeign", "feign"); for (Contributor contributor : contributors) { System.out.println(contributor.login + " (" + contributor.contributions + ")"); } } }
在Feign 底层,通过基于面向接口的动态代理方式生成实现类,将请求调用委托到动态代理实现类,基本原理如下所示:
原生的Feign只支持原生的注解,openfeign是SpringCloud项目加入了对SpringMVC注解的支持之后的版本。
详细一点来说,Feign通过FeignClientBuilder来动态构建被代理对象。在构建动态代理时,通过FeignClientFactoryBean和Feign.Builder来把@FeignClient接口、Feign相关的Configuration组装在一起。
2、根据Contract协议规则,解析接口类的注解信息,解析成内部表现:
Feign 默认有一套自己的协议规范,规定了一些注解,可以映射成对应的Http请求。
3、基于 RequestBean,动态生成Request
根据传入的Bean对象和注解信息,从中提取出相应的值,来构造Http Request 对象:
4、使用Encoder 将Bean转换成 Http报文正文(消息解析和转码逻辑)
Feign 最终会将请求转换成Http 消息发送出去,传入的请求对象最终会解析成消息体,如下所示:
5、发送Http请求
Feign 真正发送HTTP请求是委托给 feign.Client
来做的:
Feign 默认底层通过JDK 的 java.net.HttpURLConnection 实现了feign.Client接口类,在每次发送请求的时候,都会创建新的HttpURLConnection 链接,这也就是为什么默认情况下Feign的性能很差的原因。
可以通过拓展该接口,使用Apache HttpClient 或者OkHttp3等基于连接池的高性能Http客户端,我们项目内部使用的就是OkHttp3作为Http 客户端。
由于默认情况下,Feign采用的是JDK的HttpURLConnection
,所以整体性能并不高。