SpringCloud中的Feign详解
作者:silmeweed
一、简介:
Feign是一个声明式的Web Service客户端,以Java接口注解的方式调用Http请求。同时Feign整合了Ribbon和Hystrix,实现负载均衡与容断功能。
1. Feign具有如下特性:
- 可插拔的注解支持,包括Feign注解和JAX-RS注解;
 - 支持可插拔的HTTP编码器和解码器;
 - 支持Hystrix和它的Fallback;
 - 支持Ribbon的负载均衡;
 - 支持HTTP请求和响应的压缩
 - feign不支持GET请求直接传递POJO对象的.
 
2.@FeignClient注解说明
@FeignClient:是Spring识别OpenFeign客户端的注释,OpenFign客户端必须是接口。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FeignClient {
    //1.Ribbon负载均衡器的Feign客户端的名称
    @AliasFor("name")
    String value() default "";
    @AliasFor("value")
    String name() default "";
    //不使用ribbon时,请求url
    String url() default "";
    //配置响应状态码为404时是否应该抛出FeignExceptions
    boolean decode404() default false;
    //用于记录,拦截器等额外配置.
    Class<?>[] configuration() default {};
    //如果启用了Hystrix,则可以实现回退方法
    Class<?> fallback() default void.class;
    Class<?> fallbackFactory() default void.class;
    //自动给所有方法的requestMapping前加上前缀
    String path() default "";
    boolean primary() default true;
}@FeignClient(value = "common-wx", url = "www.baidu.com/common-wx")
- value/name:是将用于创建Ribbon负载均衡器的Feign客户端的名称.
 - url: 当您不使用Ribbon时,您还可以使用url属性将客户端指向目标应用程序。
 - fallback:如果启用了Hystrix,则可以实现回退方法.(底层依赖hystrix,启动类要加上@EnableHystrix)
 - configuration:用于记录,拦截器等额外配置.
 - path: 自动给所有方法的requestMapping前加上前缀,类似与controller类上的requestMapping
 - decode404:配置响应状态码为404时是否应该抛出FeignExceptions。(默认false)
 
3. HTTP客户端
OpenFeign的默认HTTP客户端HttpUrlConnection用于执行其HTTP请求。您可以配置其他客户端(ApacheHttpClient,OkHttpClient)
(1)使用OKhttp发送request
Feign底层默认是使用jdk中的HttpURLConnection发送HTTP请求,feign也提供了OKhttp来发送请求,具体配置如下:
//作用在所有Feign Client上的配置.
feign:
  client:
    config:
      default:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: basic
  okhttp:
    enabled: true
  hystrix:
    enabled: true4.构建器(启用feign客户端)
构建器是让我们创建一个客户端bean并返回一个Feign构建器。生成方式有二种:
(1) 基于面向接口的动态代理方式生成实现类。使用Feign.builder()操作类实现。
(2) 使用注解@EnableFeignClients启用feign客户端.(需要结合使用注解@FeignClient 定义一起使用)
注解@EnableFeignClients:扫描和注册feign客户端bean定义。 注解@EnableFeignClients用于告诉框架扫描所有通过注解@FeignClient定义的feign客户端。
//1.生成Bean 
@Bean
AuthClient authClient() {
    return Feign.builder()
            .client(new ApacheHttpClient())//重新使用HttpClient
            .target(AuthClient.class, baseServerUrl);
}
//2.注解方式生成Bean(需要使用注解@FeignClient 定义结合)
@EnableFeignClients(
    defaultConfiguration = DefaultFeignConfiguration.class,
    basePackages= {"com.missuteam.onepiece.oauth.api.impl"}
)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
   //扫描的包路径
    String[] value() default {};
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    //配置
    Class<?>[] defaultConfiguration() default {};
    //配置HttpClient 
    Class<?>[] clients() default {};
}
//自定义配置
@Configuration
public class DefaultFeignConfiguration {
    @Bean
    public Retryer feignRetryer() {
        return new Retryer.Default(1000,3000,3);
    }
    @Bean
    public Logger.Level feignLoggerLevel(){
        return Logger.Level.BASIC;
    }
}
//可配置的属性
public static class FeignClientConfiguration {
    private Logger.Level loggerLevel;
    private Integer connectTimeout;
    private Integer readTimeout;
    private Class<Retryer> retryer;
    private Class<ErrorDecoder> errorDecoder;
    private List<Class<RequestInterceptor>> requestInterceptors;
    private Boolean decode404;
    private Class<Decoder> decoder;
    private Class<Encoder> encoder;
    private Class<Contract> contract;
}5. Contract协议规则(接口定义时的注释规则)

(1)默认Contract 实现:
Feign 默认有一套自己的协议规范,规定了一些注解,可以映射成对应的Http请求。
| 注解 | 接口Target | 使用说明 | 
| @RequestLine | 方法上 | 定义HttpMethod 和 UriTemplate. UriTemplate 中使用{} 包裹的表达式 | 
| @Param | 方法参数 | 定义模板变量,模板变量的值可以使用名称的方式使用模板注入解析 | 
| @Headers | 类上或者方法上 | 定义头部模板变量,使用@Param 注解提供参数值的注入。如果该注解添加在接口类上,则所有的请求都会携带对应的Header信息;如果在方法上,则只会添加到对应的方法请求上 | 
| @QueryMap | 方法上 | 定义一个键值对或者 pojo,参数值将会被转换成URL上的 query 字符串上 | 
| @HeaderMap | 方法上 | 定义一个HeaderMap, 与 UrlTemplate 和HeaderTemplate 类型,可以使用@Param 注解提供参数值 | 
(2)基于Spring MVC的协议规范SpringMvcContract:
当前Spring Cloud 微服务解决方案中,为了降低学习成本,采用了Spring MVC的部分注解来完成 请求协议解析,也就是说 ,写客户端请求接口和像写服务端代码一样。目前的Spring MVC的注解并不是可以完全使用的,有一些注解并不支持,如 @GetMapping , @PutMapping 等,仅支持使用 @RequestMapping 等。
6.Feign开启GZIP压缩
Spring Cloud Feign支持对请求和响应进行GZIP压缩,以提高通信效率。开启GZIP压缩之后,Feign之间的调用数据通过二进制协议进行传输,返回值需要修改为ResponseEntity<byte[]>才可以正常显示。
//作用在所有Feign Client上的配置
feign:
  compression:
    request: #请求
      enabled: true #开启
      mime-types: text/xml,application/xml,application/json #开启支持压缩的MIME TYPE
      min-request-size: 2048 #配置压缩数据大小的下限
    response: #响应
      enabled: true #开启响应GZIP压缩7. 配置:
##################FeignClientProperties###############
#全局默认配置名称:defalut
feign.client.config.defalut.error-decoder=com.example.feign.MyErrorDecoder
feign.client.config.defalut.connectTimeout=5000
#修改全局默认配置名称为:my-config
feign.client.default-config=my-config
feign.client.config.my-config.error-decoder=com.example.feign.MyErrorDecoder
feign.client.config.my-config.connectTimeout=5000
#局部配置,@FeignClient#name=user
feign.client.config.user.error-decoder=com.example.feign.MyErrorDecoder
feign.client.config.user.connectTimeout=5000
##################FeignHttpClientProperties##################
feign.httpclient.enabled=true
feign.httpclient.connectionTimeout=5000
##################FeignClientEncodingProperties##################
# 配置请求GZIP压缩
feign.compression.request.enabled=true
# 配置响应GZIP压缩 FeignContentGzipEncodingAutoConfiguration
feign.compression.response.enabled=true
# 配置压缩支持的MIME TYPE
feign.compression.request.mime-types=text/xml,application/xml,application/json
# 配置压缩数据大小的下限
feign.compression.request.min-request-size=2048
二、原理分析
在服务调用的场景中,我们经常调用基于Http协议的服务,而我们经常使用到的框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Netty等等。(如下图)


在Feign 底层,通过基于面向接口的动态代理方式生成实现类,将请求调用委托到动态代理实现类,基本原理如下所示

到此这篇关于SpringCloud中的Feign详解的文章就介绍到这了,更多相关Feign详解内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
