上一篇《玩转OpenFeign
》介绍了OpenFeign
的一些常用配置,不过还漏了点内容。
Client连接超时、读超时的配置
这篇主要介绍如何为不同的Client
配置不同的连接超时、读超时这类参数,并从源码角度分析配置是怎么起作用的,以及都可以配置哪些参数,内容不多。
还是要从FeignAutoConfiguration
这个自动配置类说起,该配置类使用@EnableConfigurationProperties
注册了两个用于装载OpenFeign
配置的Bean
,分别是FeignClientProperties
、FeignHttpClientProperties
。
FeignHttpClientProperties
:用于配置HttpClient
。HttpClient是真正用于发起Http请求的客户端工具类。如果OpenFeign
的Client
使用的是默认的Default
,由于Default
这个Client
使用的HttpClient
是HttpURLConnection
,所以FeignHttpClientProperties
这个配置不会使用到。建议不使用默认的Default
。
如果OpenFeign
的Client
使用的是OkHttpClient
,那么FeignHttpClientProperties
则用于装载OkHttpClient
的连接池、全局连接超时配置。
FeignClientProperties
:为每个Client
配置连接超时、读超时、重试器、请求拦截器等。支持哪些配置参数可查看FeignClientProperties
的内部类FeignClientConfiguration
有哪些字段。FeignClientProperties
用于接收在application.yaml
配置文件中为每个Client
配置的连接超时、读超时、重试器、请求拦截器、编码器、解码器这类参数。
配置重试器、请求拦截器等不建议在application.yaml
中配置,因为在application.yaml
中配置重试器、请求拦截器的类名,OpenFeign
是从Spring Boot
启动应用的ApplicationContext
中根据类名获取Bean
的,并没有使用OpenFeign
提供的Client
隔离的ApplicationContext
。
除非你想全部Client
都使用相同的重试器和请求拦截器,否则不建议这样配置。既然都需要在代码中创建这些重试器、请求拦截器这些Bean
,那么直接在代码中配置不是更方法吗。在上一篇已经介绍如何通过代码方式实现为不同Client
配置不同的重试器、请求拦截器。
通过代码方式配置连接超时、读超时这些参数可通过给在Client
的ApplicationContext
注入一个Request.Options
类型的Bean
实现。
首先创建自动配置类Configuration
,往容器中注入Request.Options,给Request.Options配置连接超时和读超时,如下图所示。
不要在这个配置类上并@Configuration注解,因为这不是注册到应用的ApplicationContext,而是注册到OpenFeign为Client创建的ApplicationContext。
最后给@FeignClient
注解的configuration
属性添加这个配置类。
再来看下如何在application.yaml
中配置Client的连接超时、读超时这些参数。
接收feign.client.config
配置的类为FeignClientConfiguration
。
config字段是个map
,支持多个配置,每个Client
配置的key
为Client
的名称(服务提供者名称),value
类型为FeignClientConfiguration
。支持配置连接超时(connectTimeout
)、读超时(readTimeout
)等参数。
从源码分析配置是怎么生效的
OpenFeign
会将使用@FeignClient
注解注释的接口扫描出来,并往每个Client
各自的ApplicationContext
注入一个FeignClientFactoryBean
,该FeignClientFactoryBean
的getObject
方法返回的是接口的代码对象。
FeignClientFactoryBean
在创建接口的代理对象时,会先生成一个Feign.Builder
,然后使用这个Feign.Builder
创建代理对象。
FeignClientFactoryBean
在创建Feign.Builder
后会读取配置,将配置写入到Feign.Builder
,Feign.Builder
在创建代理对象时就会使用上这些配置,最后用于创建方法拦截器SynchronousMethodHandler
。
FeignClientFactoryBean为Feign.Builder
填充配置的源码如下。
从上面源码可以看出,我们在application.yaml
中配置default-to-properties
为true
实际目的是不要让默认配置覆盖我们在application.yaml
中添加的配置。
如果项目中使用Ribbon
,那么FeignRibbonClientAutoConfiguration
会注入一个Request.Options
,当default-to-properties
配置为false
时,这个Request.Options
就会覆盖application.yaml
中添加的配置。所以要将default-to-properties
配置为true
,配置才生效。
从上面源码还发现一个参数inheritParentContext
,这个inheritParentContext
的值默认为true
。当配置inheritParentContext
为false
时,我们在application.yaml
中添加的配置就都不会生效。
如果想要将inheritParentContext
设置为false
,该如何设置呢?
在@FeignClient
注解的configuration
属性指定的配置类中注入一个FeignClientConfigurer
类型的Bean
,实现FeignClientConfigurer
接口的inheritParentConfiguration
方法,在方法中返回false
即可。
实际我们关心的还是创建出来的代理对象的方法拦截器(SynchronousMethodHandler
)。在创建SynchronousMethodHandler
时Feign.Builder
会将封装了连接超时、读超时配置的Request.Options
对象传递给SynchronousMethodHandler
。在发起请求时,由SynchronousMethodHandler
将Request.Options
配置对象传给Client
,如OkHttpClient
。
每种Client
实现的方式不同,OkHttpClient
的实现是,当全局配置的连接超时与当前Client
配置的连接超时不同时,重新创建HttpClient,即重新创建用于真正发起Http请求的OkHttpClient
,使用的还是相同的连接池。