引言
Hello 大家好,这里是Anyin。
在上一篇又解锁了一种OpenFeign的使用方式! 我们知道了对于第三方的http类型的对接,我们可以通过FeignClient
进行对接,只需要配置好对应的编解码器和拦截器,基本就可以搞定。
但是,需求总是变化的。这种方式是需要把对应的配置写在配置文件中,然后在应用启动的时候,通过@EnableFeignClients
注解去装配FeignClient
实例;如果我们对接的是多家的供应商,并且遵循一套相同的协议,那么就需要我们实现动态的增加FeignClient
实例,即相关配置秘钥等从数据库读取,然后动态加载FeignClient
实例。
那这个能实现吗? 肯定能!
源码分析
默认的流程
我们先梳理下之前的流程是什么。
- 通过
@EnableFeignClients
注解去扫码所有带@FeignClient
注解的接口 - 在
FeignClientsRegistrar#registerFeignClient
方法上实现创建FeignClient的接口代理类 - 在
FeignClientFactoryBean#getTarget
方法上实现具体装配工作。
其中,在getTarget方法上我们可以看到,源码从spring容器的上下文中获取一个FeignContext
实例,然后在feign方法内,通过FeignContext
从子容器中获取到对应的编解码器、拦截器等,装配Feign.Builder
实例。代码如下:
思考
按我之前的想法是在FeignContext
中把对应的配置类加载到configurations
属性中,这个是保存了每个FeignClient
实例的配置项。

这里的泛型C就是FeignClientSpecification
实例,然后设置到。 也就是说,在FeignContext
实例化之后,当数据库关于第三方对接的配置信息出现变更的时候,我手动的实例化FeignClientSpecification
实例,然后设置到FeignContext
实例即可。
以下是OpenFeign关于FeignContext
的实例化方式
我们再继续查看FeignClientSpecification
类的源码,我们发现了一个很头疼的事情,它是一个包访问级别。
所以想通过这个方式来实现动态增减FeignClient
实例是行不通了。
继续思考
再一次翻看OpenFeign
源码,我们发现了一个类:FeignClientBuilder
,通过它我们可以拿到一个FeignClient的代理类(我们编写接口的实现),但是它只有几个属性可以配置,如下:
虽然有了url、contextId、fallback、path等属性,但是我们最想要的编解码器、拦截器却没有。
但是我们再认真看看代码,会发现一个customize
方法,顾名思义应该是自定义配置,它的入参是一个函数式接口FeignBuilderCustomizer
,如下:
观察它的接口签名,你会发现有意思的来了,它的形参竟然是Feign.Builder
!!!
通过该实例,我们就可以配置我们自定义的编解码和拦截器了。我们回头想想FeignClientFactoryBean#feign
方法,它就是通过Feign.Builder
配置编解码和拦截器的。
在FeignClientFactoryBean#feign
方法内,它还执行了一个applyBuildCustomizers
,该方法内就是执行自定义操作,它就是我们在FeignClientBuilder
配置进去的FeignBuilderCustomizer
实例。
自此,整个思路和流程打通 !!!
代码实现
- 根据供应商标识获取对应的供应商配置信息
- 根据供应商配置信息装配
FeignClient
实例
- 配置自定义信息
最后
以上就是个人对动态增减FeignClient
实例的一点思考,如果有什么问题欢迎讨论。