Spring Cloud OpenFeign源码解析 - 知乎
@EnableFeignClients
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(FeignClientsRegistrar.class)
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<?>[] defaultConfiguration() default {};
Class<?>[] clients() default {};
}
@FeignClientsRegistrar
实现了spring 的接口ImportBeanDefinitionRegistrar,可以在启动时动态的生成BeanDefinition,并注册到BeanDefinitionRegistry,后续ApplicationContext可以根据这些BeanDefintion实例化Bean,并且注册到容器中。
简单来说,通过FeignClientsRegistrar
,可以做到在应用开发者只提供接口的情况下,框架自动实现接口,并且自动注册到容器中。
实现接口ResourceLoaderAware,主要讲ApplicationContext 的resourceLoader 传入到FeignClientRegistrar中,resourceLoader主要用于包扫描,资源加载。
实现接口EnvironmentAware,将ApplicationContext 中的Environment 传入FeignClientRegistrar 中,和配置相关的数据通过Environment 提取。
registerBeanDefinitons 里面有两个方法,第一个是registerDefaultConfiguration,将defaultConfiguration 注册到BeanDefintionRegitry.@EnableFeignClients
的参数defaultConfiguration 在此地起作用。
registerFeignClients 主要干了几件事:
1.构造扫描器,ClassPathScanningCandiateComponentProvider,用于在包路径上找到候选组件,也就是FeignClient
接口
2.给扫描器添加过滤器
3.扫描找到所有的候选组件,并将注解@FeignClient 对应的configuration 注册到BeanDefinationRegistry,将注解的参数作为BeanDefinition 的参数,将FeignClientFactoryBean 注册到BeanDefinitionRegistry
FeignClientFactoryBean
对于构建一些比较复杂bean,BeanDefinition 不是特别方便,spring 提供了一个特殊的接口,factoryBean,可以将复杂的bean 写在factorybean实现类上。
方法getObject 调用了getTarget()创建FeignClient, 主要包括 1. 从applicationContext 中取出feigncontext, 2.从feigncontext中取出当前的contextId 的feign.build,并且配置编解码器,拦截器,日志打印级别等。3. 通过url是否为空,判断是否为rpc 请求,如果是rpc 请求,使用负载均衡客户端。
2.4.1 Feign.Builder
ParseHandlersByName:对FeignClient接口的每个方法创建一个处理器MethodHandler
InvocationHandlerFactory :创建一个动态处理器工厂。