【OpenFeign】【源码+图解】【一】HelloWorld及其工作原理
目录
- 3. 注册OpenFeign接口的实例
3. 注册OpenFeign接口的实例
从HelloWorld中我们看到需要显示加入**@EnableFeignClients注解才能开启openFeign的功能,因此它就成为我们分析openFeign**的入口,先看下这个Annotation的属性
@Import(FeignClientsRegistrar.class) // 这个注册类是关键
public @interface EnableFeignClients {
// 扫描的包,用于寻找open-feign客户端
String[] value() default {};
// 与value()一样
String[] basePackages() default {};
// 与value()的字符串不同,这里用的是Class类
Class<?>[] basePackageClasses() default {};
// 这里声明的配置会在所有的open-feign的clients生效
Class<?>[] defaultConfiguration() default {};
// @FeignClient声明的类,如果不为空的话前面的包扫描会失效
Class<?>[] clients() default {};
}
先看下FeignClientsRegistrar的类图
从类图中可以看出FeignClientsRegistrar有以下作用
- 注册beans
- 获取配置Environment
- 获取资源加载器ResourceLoader
那么,接下来我们就开始分析FeignClientsRegistrar要注册哪些beans,入口是实现ImportBeanDefinitionRegistrar接口的registerBeanDefinitions
方法
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
// 1、注册默认的配置,即@EnableFeignClients中的defaultConfiguration,这个是所有FeignClients都有的
registerDefaultConfiguration(metadata, registry);
// 2、注册FeignClients
registerFeignClients(metadata, registry);
}
}
整体过程如下
中间涉及的源码过多,不做过多的具体分析,只探讨绿色的两部分,因为这两部分也是后续的开始
在开始之前我们先认识下**@FeignClient**
public @interface FeignClient {
// client名字
@AliasFor("name")
String value() default "";
// context名字
String contextId() default "";
@AliasFor("value")
String name() default "";
// 别名
String[] qualifiers() default {};
// 类似@RequestMapping声明的base url
String url() default "";
boolean decode404() default false;
// client的配置,不同于@EnableFeignClients的defaultConfiguration,这个configuration只属于某个client
Class<?>[] configuration() default {};
// 降级处理的实例,需实现FeignClient
Class<?> fallback() default void.class;
// 降级处理实例的创建工厂,需实现FallbackFactory接口
Class<?> fallbackFactory() default void.class;
String path() default "";
boolean primary() default true;
}
在使用中**@FeignClient**是用在接口上,而接口需要实例化才能使用,而绿色的两部分就是创建接口实例的过程,接下来分析是怎么利用其参数来创建实例的
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata,
Map<String, Object> attributes) {
......
// 本代码以HelloWorld中的ProductFeignClient为例探讨
FeignClientFactoryBean factoryBean = new FeignClientFactoryBean();
factoryBean.setBeanFactory(beanFactory); // DefaultListableBeanFactory
factoryBean.setName(name); // product
factoryBean.setContextId(contextId); // product
factoryBean.setType(clazz); // interface com.lanna.openfeign.ProductFeignClient
factoryBean.setRefreshableClient(isClientRefreshEnabled()); // yml文件中的feign.client.refresh-enabled
BeanDefinitionBuilder definition = BeanDefinitionBuilder.genericBeanDefinition(clazz, () -> {
factoryBean.setUrl(getUrl(beanFactory, attributes)); // @FeignClient.url,默认""
factoryBean.setPath(getPath(beanFactory, attributes)); // @FeignClient.path,默认""
// @FeignClient.decode404,默认false。如果为true,当遇到404错误时不直接抛异常
factoryBean.setDecode404(Boolean.parseBoolean(String.valueOf(attributes.get("decode404"))));
Object fallback = attributes.get("fallback");
// @FeignClient.fallback。fallback类必须实现@FeignClient的接口并且在spring的容器中
if (fallback != null) {
factoryBean.setFallback(fallback instanceof Class ? (Class<?>) fallback
: ClassUtils.resolveClassName(fallback.toString(), null));
}
// @FeignClient.fallbackFactory。fallbackFactory:
// 1、必须实现FallbackFactory接口,2、必须能创建@FeignClient接口的实例,3、必须在spring的容器中
Object fallbackFactory = attributes.get("fallbackFactory");
if (fallbackFactory != null) {
factoryBean.setFallbackFactory(fallbackFactory instanceof Class ? (Class<?>) fallbackFactory
: ClassUtils.resolveClassName(fallbackFactory.toString(), null));
}
// 创建@FeignClient接口(即ProductFeignClient)的proxy实例
return factoryBean.getObject();
});
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
// 设置延迟初始化。如果声明的FeignClient没有使用的话不会初始化
definition.setLazyInit(true);
// 验证参数
validate(attributes);
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
// factoryBeanObjectType: com.lanna.openfeign.ProductFeignClient
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
// feignClientsRegistrarFactoryBean: factoryBean
beanDefinition.setAttribute("feignClientsRegistrarFactoryBean", factoryBean);
// @FeignClient.primary,默认true
beanDefinition.setPrimary(primary);
// 别名qualifiers:@FeignClient.qualifiers
BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, qualifiers);
// 注册com.lanna.openfeign.ProductFeignClient
BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);
// 如果feign.client.refresh-enabled开启(默认false),注册名为contextId的OptionsFactoryBean
registerOptionsBeanDefinition(registry, contextId);
}
}
注册OpenFeign的beans实例过程就分析到此,代码中definition.setLazyInit(true)
设置了延迟加载,通俗点理解就是如果代码中没有通过@Autowired
注入bean的话是不会调用factoryBean.getObject()
的。接下来我们就看看factoryBean.getObject()是如何创建FeignClient的client,即ProductFeignClient的实例。