OpenFeign的核心组件
通常我们在阅读OpenFeign的源码时,可以通过两条路来理解:
1)@FeignClient注解修饰的接口类是如何创建,实例化的
2)调用FeignServiceClient对象的网络请求的相关函数时,OpenFeign是怎么发送请求的
因此,OpenFeign相关的类也可以大致归为:类实例化相关的和发送网络请求相关的
如下图(OpenFeign关键类类图):
其中,比较重要的是:Fe ignClientFactoryBean、FeignContext和SynchronousMethodHandler。
1)FeignClientFactoryBean:是创建 FeignClient 修饰的接口类 Bean 实例的工厂类
2)FeignContext 是配置组件的上下文环境,保存着相关组件的不同实例,这些实例由不同的 FeignConfiguration 配置类构造出来
3)SynchronousMethodHandler:是MethodHandler的子类,可以在 FeignClient 相应方法被调用时发送网络请求,然后再将请求响应转化为函数返回值进行输出
后面在跟踪源码的时候可以按照如下顺序来理解
:
动态注册(BeanDefinition)——> 实例初始化 ——> 函数调用和网络请求
1)动态注册(BeanDefinition)
OpenFeign可以通过相关配置进行多种自定义化,不通的配置会导致初始化不同的bean实例,从而控制OpenFeign调用时的具体行为,比如网络请求的编解码,压缩和日志等等。
a. FeignClientsRegistrar
所有的OpenFeign 的相关操作都是从@
EnableFeignClients 开始的。@EnableFeignClients 有三个作用:
一是引入
FeignClientsRegistrar
;二是指定扫描
Feign
Client
的包信息,就是指定
Feign
Client
接口类
所在的包名;
三是
指定 F
eignClient
接口
的自定义配
置类。
@
EnableF
eignClients
注解的定
义如下:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
//ImportBeanDef nitionRegistrar 的子类 用于处理由FeignCl ent 注解
@Import({FeignClientsRegistrar.class})
public @interface EnableFeignClients {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
//指定自定义 feign cl ent 的自定义配置,Fe gnClientsConf guration是默认的配置类
Class<?>[] defaultConfiguration() default {};
// 指定被自FeignClie 修饰的类,如果不为空,那么路径自动检测机制会被关闭
Class<?>[] clients() default {};
}
FeignClientsRegistrar是
ImportBeanDefi
ni
ti
onRegi
strar的
子类,
Spring用
ImportBeanDefinitionRegistrar来
动态注册BeanDefinition。
Ope
nFeign
通过F
eignClientsRegistrar
来处理@F
eign
Client
修饰的F
eignClient
类,并将这些类的
BeanDe
finition注
册到
Spring
中,这样就可以使用
Auto
wired
式来自动装载这些F
eign
Client接口类的
Bean实例。
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
...
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
this.registerDefaultConfiguration(metadata, registry);
this.registerFeignClients(metadata, registry);
}
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
} else {
name = "default." + metadata.getClassName();
}
this.registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
}
}
...
}
其中,这个registerBeanDefinitions主要做了两个事情:一是注册@EnableFeignClients 提供的自定义配置类中的相关Bean实例,二是根据 @EnableFeignClients 提供的包信息扫描@FeignClient 注解修饰的 FeignClient接口类,然后进行 Bean 实例注册。
@EnableFeignClients 的自定义配置类是@Configuration 解修饰的配置类,它会提供一系列组装 FeignClient 的各种组件实例。这些组件包括:Client、Target、Decoder、Encoder和Contract 等。我们再看下registerDefaultConfiguration 的代码:
private void registerDefaultConfiguration(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//获取到metadata 中关于EnableFeignClients的属性值键值对
Map<String, Object> defaultAttrs = metadata.getAnnotationAttributes(EnableFeignClients.class.getName(), true);
//如果EnableFeignClients 配置了defaultConfiguration 类,那么才进行下一步操作,如果没有,会使用默认的FeignConfiguration
if (defaultAttrs != null && defaultAttrs.containsKey("defaultConfiguration")) {
String name;
if (metadata.hasEnclosingClass()) {
name = "default." + metadata.getEnclosingClassName();
} else {
name = "default." + metadata.getClassName();
}
this.registerClientConfiguration(registry, name, defaultAttrs.get("defaultConfiguration"));
}
}
再看下: this.registerClientConfiguration这个方法: