
SpringCloud原理 OpenFeign之FeignClient动态代理生成原理三
二、Feign客户端接口动态代理的生成源码剖析
(1)FeignAutoConfiguration源码剖析
FeignAutoConfiguration是feign在整个springcloud的配置类,我拎出这里面比较核心的代码。
注入了一堆FeignClientSpecification,FeignClientSpecification这玩意就是上文提到的调用registerClientConfiguration的时候注入到spring容器中的,一个Feign客户端的配置一个FeignClientSpecification,所以是个集合,然后封装到FeignContext中,最后将FeignContext注入到spring容器中。
FeignContext也是很重要的一个东西,我们来分析一下它的源码
FeignContext继承了NamedContextFactory,构造的时候,传入了FeignClientsConfiguration,这个玩意也很重要,别急,我们慢慢来分析它们的作用。
(2)NamedContextFactory源码剖析
我先来说结论,NamedContextFactory的作用是用来进行配置隔离的,ribbon和feign的配置隔离都依赖这个抽象类。
何为配置隔离,因为每个Feign客户端都有可能有自己的配置,从@FeignClient注解的属性configuration可以看出,所以写了这个类,用来隔离每个客户端的配置,这就是为什么在构造FeignContext传入一堆FeignClientSpecification的原因,这里封装了每个客户端的配置类。
那是怎么实现的呢,我拎出来一部分核心的源码,不重要的我就忽略了。
分析一下每个成员变量的作用:
contexts:一个客户端一个对应的AnnotationConfigApplicationContext
configurations:一个客户端一个配置类的封装,对应到Feign的就是FeignClientSpecification
parent:springboot真正启动的就是这个ApplicationContext
defaultConfigType:默认的配置类,对应Feign就是构造FeignContext是传入的FeignClientsConfiguration
分析一下核心的方法:
getContext:这个方法很简单,就是根据客户端名称从contexts获取对应的AnnotationConfigApplicationContext,获取不到就去创建一个,然后放入contexts
createContext:就是直接new了一个AnnotationConfigApplicationContext对象,然后按照按照配置的优先级顺序,一步步放入配置类,最后放入parent容器,也就是说每个客户端对应的容器,都有一个共同的父容器,同时如果每个客户端对应的容器获取不到的配置,都会再次从父容器中获取。这个结论还是很重要的。
其实所谓的配置隔离就是为每个客户端构建一个AnnotationConfigApplicationContext,然后基于这个ApplicationContext来解析配置类,这样就实现了配置隔离。
不知道大家有么有遇到过这个坑,就是在spring cloud环境中,监听类似ContextRefreshedEvent这种事件的时候,这个事件会无缘无故地触发很多次,其实就是这个原因就在这,因为spring的事件是有传播机制的,每个客户端对应的容器都要进行refresh,refresh完就会发这个事件,然后这个事件就会传给parent容器,也就是springboot启动的容器,就会再次触发,所以如果客户端很多,那么就会触发很多次。解决办法就是进行唯一性校验,只能启动一次就行了。
文章转自公众号:三友的java日记
