Feign 是一个声明式的 Web 服务客户端,它使 Java 编写 Web 服务客户端变得更加容易。其实就是通过 JDK 代理生成接口的代理对象,方法的执行就是执行 Http 请求。而 OpenFeign 的作用是通过自动装配将 Feign 集成到应用程序中。主要是有这几个特性:
- 整合 Spring Cache ,代理 FeignClient 接口方法,增加上缓存相关的逻辑。
- 整合 CircuitBreaker ,代理 FeignClient 接口方法,方法的执行委托给 CircuitBreaker 控制
- 整合 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


1230

被折叠的 条评论
为什么被折叠?



