又又解锁了一种OpenFeign的使用方式!

引言

Hello 大家好,这里是Anyin。

在上一篇又解锁了一种OpenFeign的使用方式! 我们知道了对于第三方的http类型的对接,我们可以通过FeignClient进行对接,只需要配置好对应的编解码器和拦截器,基本就可以搞定。

但是,需求总是变化的。这种方式是需要把对应的配置写在配置文件中,然后在应用启动的时候,通过@EnableFeignClients注解去装配FeignClient实例;如果我们对接的是多家的供应商,并且遵循一套相同的协议,那么就需要我们实现动态的增加FeignClient实例,即相关配置秘钥等从数据库读取,然后动态加载FeignClient实例。

那这个能实现吗? 肯定能!

源码分析

默认的流程


我们先梳理下之前的流程是什么。

  1. 通过@EnableFeignClients注解去扫码所有带@FeignClient注解的接口
  2. FeignClientsRegistrar#registerFeignClient方法上实现创建FeignClient的接口代理类
  3. FeignClientFactoryBean#getTarget方法上实现具体装配工作。

其中,在getTarget方法上我们可以看到,源码从spring容器的上下文中获取一个FeignContext实例,然后在feign方法内,通过FeignContext从子容器中获取到对应的编解码器、拦截器等,装配Feign.Builder实例。代码如下:

image.png

思考


按我之前的想法是在FeignContext中把对应的配置类加载到configurations属性中,这个是保存了每个FeignClient实例的配置项。

image.png

这里的泛型C就是FeignClientSpecification实例,然后设置到。 也就是说,在FeignContext 实例化之后,当数据库关于第三方对接的配置信息出现变更的时候,我手动的实例化FeignClientSpecification实例,然后设置到FeignContext实例即可。

以下是OpenFeign关于FeignContext的实例化方式

image.png

我们再继续查看FeignClientSpecification类的源码,我们发现了一个很头疼的事情,它是一个包访问级别。

image.png

所以想通过这个方式来实现动态增减FeignClient实例是行不通了。

继续思考


再一次翻看OpenFeign源码,我们发现了一个类:FeignClientBuilder,通过它我们可以拿到一个FeignClient的代理类(我们编写接口的实现),但是它只有几个属性可以配置,如下:

image.png

虽然有了url、contextId、fallback、path等属性,但是我们最想要的编解码器、拦截器却没有。

但是我们再认真看看代码,会发现一个customize方法,顾名思义应该是自定义配置,它的入参是一个函数式接口FeignBuilderCustomizer,如下:

image.png

观察它的接口签名,你会发现有意思的来了,它的形参竟然是Feign.Builder !!!

通过该实例,我们就可以配置我们自定义的编解码和拦截器了。我们回头想想FeignClientFactoryBean#feign方法,它就是通过Feign.Builder配置编解码和拦截器的。

image.png

FeignClientFactoryBean#feign方法内,它还执行了一个applyBuildCustomizers,该方法内就是执行自定义操作,它就是我们在FeignClientBuilder配置进去的FeignBuilderCustomizer实例。

自此,整个思路和流程打通 !!!

代码实现

  1. 根据供应商标识获取对应的供应商配置信息

image.png

  1. 根据供应商配置信息装配FeignClient实例

image.png

  1. 配置自定义信息

image.png

最后

以上就是个人对动态增减FeignClient实例的一点思考,如果有什么问题欢迎讨论。

猜你喜欢

转载自juejin.im/post/7107514972585852958