Spring Cloud OpenFeign 介绍

Feign 是一个声明式的 Web 服务客户端,它使 Java 编写 Web 服务客户端变得更加容易。其实就是通过 JDK 代理生成接口的代理对象,方法的执行就是执行 Http 请求。而 OpenFeign 的作用是通过自动装配将 Feign 集成到应用程序中。主要是有这几个特性:

  1. 整合 Spring Cache ,代理 FeignClient 接口方法,增加上缓存相关的逻辑。
  2. 整合 CircuitBreaker ,代理 FeignClient 接口方法,方法的执行委托给 CircuitBreaker 控制
  3. 整合 spring-cloud-loadbalancer ,让 Feign 使用负载均衡的 HTTP 客户端 发送请求

核心功能源码分析

OpenFeign 自动装配原理

spring-cloud-openfeign-core.jar!META-INF/spring.factories 的部分内容

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
       org.springframework.cloud.openfeign.FeignAutoConfiguration,\
       org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
       org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration,\
       org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoConfiguration

FeignAutoConfiguration

主要是注册了 FeignContext、Targeter、CachingCapability、Client:

  • FeignContext 是用来隔离不同 FeignClient 的容器,每个 FeignClient 有单独的 IOC 容器,容器中默认注册了 FeignClient 需要的 bean。
  • Targeter 是用来生成 FeignClient 接口实现类的,只是配置而已。生成接口代理类的逻辑是由 Feign 实现的。
  • CachingCapability 是用来配置 Feign.Builder 的,主要是对 InvocationHandlerFactory 进行增强,而 InvocationHandlerFactory 是用来生成 InvocationHandler 从而让方法的执行委托给 CacheInterceptor 执行,这是属于 SpringCache 的内容了,不展开说了。
  • Client 是执行 HTTP 请求的工具,比如 ApacheHttpClient、OkHttpClient。
/**
 * FeignAutoConfiguration
 *      注册三个绑定属性的bean @EnableConfigurationProperties({ FeignClientProperties.class, FeignHttpClientProperties.class, FeignEncoderProperties.class})
 *          FeignClientProperties:记录 FeignClient 的配置信息,比如 RequestInterceptor 等等
 *          FeignHttpClientProperties:记录 HttpClient 的配置信息,最大连接数、连接的ttl等等
 *          FeignEncoderProperties: 是否从响应头 Content-Type 获取响应体的编码,会使用这个编码对响应体解码成字符串(默认是UTF-8)
 *
 *      注册 HasFeatures 是用来描述系统有 Feign 的功能,它是给 FeaturesEndpoint 使用的。
 *
 *      注册 FeignContext 其继承 NamedContextFactory。
 *        其作用是会根据 name 创建单独的IOC容器,获取bean是从单独的IOC容器中拿。IOC容器默认有两个配置类:PropertyPlaceholderAutoConfiguration、FeignClientsConfiguration
 *        并依赖 FeignClientSpecification 用来扩展配置类,创建的IOC容器会缓存到Map中。
 *
 *        FeignClientsConfiguration 其目的是注册 Decoder、Encoder、Encoder、Contract、FormattingConversionService、
 *        Retryer、FeignLoggerFactory、FeignClientConfigurer、Feign.Builder 这些bean 而且都有 @ConditionalOnMissingBean 条件,若我们想自定义
 *        这些bean,可以设置 FeignClientSpecification 扩展配置类,从而让 @ConditionalOnMissingBean 不满足,也就不会使用这些默认的bean
 *
 *        而 FeignClientSpecification 可以通过这两个注解快速配置
 *         @EnableFeignClients(defaultConfiguration={A.class}) // 这样子是注册全局的,FeignContext 创建的所有IOC容器都会使用这个配置类
 *         @FeignClient(contextId="f1",name="serviceName",configuration={A.class}) // FeignContext 为 f1 创建的IOC容器 会使用这个配置类
 *          注:contextId 为空 就会使用 name 作为缺省值
 *
 *      注册 CachingCapability 其实现 Capability 接口,依赖 CacheInterceptor。CachingCapability 是用来增强 Feign.Builder 设置的 InvocationHandlerFactory 的
 *          让方法的执行委托给 CacheInterceptor 执行,也就是支持 Spring Cache 的功能
 *
 *      注册 PageJacksonModule、SortJacksonModule 都是 Module 类型的,这两个东西是用来扩展 jackson 扩展序列化规则的,是为了支持 spring data
 *
 *      注册 Targeter 类型的bean,默认是 DefaultTargeter , 如果容器中有 CircuitBreakerFactory 类型的bean,那就会注册 FeignCircuitBreakerTargeter
 *          Targeter 是用来聚合 FeignClientFactoryBean、Feign.Builder、FeignContext、Target.HardCodedTarget,
 *                   定义了如何生成 Target.HardCodedTarget<T> 泛型的实例
 *
 *      注册 CircuitBreakerNameResolver 是用来生成断路器name的,FeignCircuitBreakerTargeter 会依赖这个bean
 *
 *      注册 HttpClientConnectionManager 会依赖 FeignHttpClientProperties 来设置连接相关参数
 *
 *      注册 CloseableHttpClient 是 HttpClient 的实现类,其依赖 HttpClientConnectionManager、FeignHttpClientProperties 设置一些参数
 *
 *      注册 ApacheHttpClient 是 feign.Client 的实现类,依赖 HttpClient 来执行HTTP请求
 *
 *      属性 feign.okhttp.enabled == true 会注册
 *          注册 ConnectionPool 会依赖 FeignHttpClientProperties 来设置连接相关参数
 *          注册 okhttp3.OkHttpClient 其依赖 ConnectionPool、FeignHttpClientProperties 设置一些参数
 *          注册 OkHttpClient 是 feign.Client 的实现类,依赖 okhttp3.OkHttpClient 来执行HTTP请求
 * */

FeignAcceptGzipEncodingAutoConfiguration

/**
 * FeignAcceptGzipEncodingAutoConfiguration
 *      注册 FeignAcceptGzipEncodingInterceptor , 它是 RequestInterceptor 的实现类,其目的是给 Request 增加请求头 Accept-Encoding=gzip,deflate
 *          注:请求头 Accept-Encoding=gzip,deflate 是告诉服务器 客户端支持 gzip,deflate 压缩
 **/
feign:
  compression:
    # 设置请求头 Accept-Encoding=gzip,deflate 用于告诉服务器 客户端支持 gzip,deflate 压缩
    response:
      enabled: true

FeignContentGzipEncodingAutoConfiguration

/**
 * FeignContentGzipEncodingAutoConfiguration
 *      注册 FeignContentGzipEncodingInterceptor , 它是 RequestInterceptor 的实现类,其目的是给 Request 增加请求头 Content-Encoding=gzip,deflate
 *          满足这两点才需要增加请求头:
 *              1. Content-Type 是属性 feign.compression.request.mimeTypes 包含的值
 *              2. Content-Length 大于 属性 feign.compression.request.minRequestSize 的值
 *
 *          请求头有 Content-Encoding=gzip,deflate 会对请求体进行编码后(压缩)再发送给到服务器(这得看你用的Client是否支持)
 * */
feign:
  compression:
    request:
      enabled: true
      # FeignClient 执行HTTP请求时,Content-Type 、Content-Length 满足这两个条件,就设置请求头 Content-Encoding=gzip,deflate。
      # 设置了请求头后 在发送前会对请求体进行压缩
      mimeTypes:
        - 'text/xml'
        - 'application/xml'
        - 'application/json'
      minRequestSize: 100

FeignLoadBalancerAutoConfiguration

@Import({
   
    HttpClientFeignLoadBalancerConfiguration.class, OkHttpFeignLoadBalancerConfiguration.class,
        DefaultFeignLoadBalancerConfiguration.class })
public class FeignLoadBalancerAutoConfiguration {
   
   }
/**
 * FeignLoadBalancerAutoConfiguration
 *
 *      目的都是注册 Client 的实现类,根据条件会注册 FeignBlockingLoadBalancerClient 或者是 RetryableFeignBlockingLoadBalancerClient
 *         导入的三个配置类的区别在于:
 *          - HttpClientFeignLoadBalancerConfiguration  依赖 HttpClient 执行HTTP请求
 *          - OkHttpFeignLoadBalancerConfiguration  依赖 okhttp3.OkHttpClient 执行HTTP请求
 *          - DefaultFeignLoadBalancerConfiguration  依赖 Client.Default 执行HTTP请求
 * */

@EnableFeignClients 和 @FeignClient

@EnableFeignClients 是用来扫描得到标注了 @FeignClient 的类,将类的信息映射成 BeanDefinition,然后注册到 BeanFactory 中。而需要注意的是这个 bean 的实例化是 FeignClientFactoryBean.getObject() 得到的。@FeignClient 的注解值主要是映射给FeignClientFactoryBean。所以要想知道 @FeignClient 是如何实现生成接口代理对象的还得看FeignClientFactoryBean.getObjec()

@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
   
   

    String[] value() default {
   
   }; // 要扫描的包

    String[] basePackages() default {
   
   }; // 要扫描的包

    Class
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小新杂谈社

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值