关于Feign

一.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,所以整体性能并不高。

 


原文地址:https://www.cnblogs.com/ZJOE80/p/13022647.html