目录
一、前言
二、初始化OpenFeign的入口
1、ImportBeanDefinitionRegistrar接口
2、分岔路口你该往哪走
3、将ImportBeanDefinitionRegistrar添加到configurationClasses
3.1、getImports(sourceClass)
3.2、processImports()
4、Bean定义注册入口
4.1、loadBeanDefinitions()逻辑
4.2、loadBeanDefinitionsForConfigurationClass()逻辑
4.3、loadBeanDefinitionsFromRegistrars()逻辑
4.4、ImportBeanDefinitionRegistrar接口的registerBeanDefinitions()逻辑
学过SpringCloud的都知道使用OpenFeign都要在SpringBoot启动类上面加上@EnableFeignClients这个注解,而这个注解内部也使用了@Import注解导入FeignClientsRegistrar.class,是ImportBeanDefinitionRegistrar的实现类。
那么会不会也跟前面讲解的SpringBoot自动装配一样呢?感觉是一样,又好像不一样,@EnableFeignClients是spring-cloud-openfeign提供的注解,里里外外都没有使用到SpringBoot的东西,但是用到了Spring的ImportBeanDefinitionRegistrar等接口。那么答案究竟是什么,下面将一一解开。
借用一下之前Bean定义注册流程图,具体的可自行去画一下。
注意:一部分流程在前面已经讲解,这里不会过多赘述。重点讲解Spring中的ImportBeanDefinitionRegistrar接口及其涉及的一些流程。
public interface ImportBeanDefinitionRegistrar {
/**
* 根据导入@Configuration 类的给定注释元数据,根据需要注册 bean 定义。
*
*
* 注意,由于与@Configuration 类处理相关的生命周期约束,BeanDefinitionRegistryPostProcessor 类型
* 可能 < em > 不 在这里注册。
*
*
* 默认实现委托给 # registerBeanDefinition(AnnotationMetadata,BeanDefinitionRegistry)。
*/
default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
/**
* Register bean definitions as necessary based on the given annotation metadata of
* the importing {@code @Configuration} class.
*
Note that {@link BeanDefinitionRegistryPostProcessor} types may not be
* registered here, due to lifecycle constraints related to {@code @Configuration}
* class processing.
*
The default implementation is empty.
* @param importingClassMetadata annotation metadata of the importing class
* @param registry current bean definition registry
*/
default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
}
}
Spring在处理ImportBeanDefinitionRegistrar接口时像处理@Configuration注解一样,那么之前的Bean定义注册文章读者可知道走的是哪个流程了。
ImportBeanDefinitionRegistrar接口翻译过来就是“导入Bean定义登记员”,那么它的方法就是处理登记的,并且登记的是一批Bean定义。那么具体的逻辑就交给它的实现类去实现相应细节。从接口方法的两个参数,可发现登记员会不会把最终的登记委托给BeanDefinitionRegistry的方法做真正的登记呢。在之前的文章确实是这样的,登记处在(BeanDefinitionRegistry的实现类)DefaultListableBeanFactory的beanDefinitionMap字段中。
ImportBeanDefinitionRegistrar 通常和@Import注解配合使用,@Import注解将ImportBeanDefinitionRegistrar的实现类注入到@Import所属根类的ConfigurationClass属性中,在注册跟类的BeanDefinition时,会遍历调用其@Import的所有ImportBeanDefinitionRegistrar接口的 registerBeanDefinitions()方法。
虽然说ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(registry)内部会处理两大类Bean定义,调用this.reader.loadBeanDefinitions(configClasses)处理@Configuration下的Bean定义,但是调用前需要获取configClasses这个集合。故需要进到ConfigurationClassParser#parse()解析启动类这个逻辑,解析后才能获取configClasses去处理Bean定义注册。下面就是围绕这两大方向去讲解的。
跟进ConfigurationClassParser#parse()
进入到doProcessConfigurationClass()核心方法。内部有个处理任何@Import注释的processImports()
方法,SpringBoot自动装配文章中也已经讲过了,这里补充一下。
可见processImports()中的
getImports(sourceClass)内部调用的collectImports()解析启动类中用到的注解,就把@Import中的类添加到imports集合(详细SpringBooot自动装配已讲解)。其中就有FeignClientRegistrar。
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection importCandidates, Predicate exclusionFilter,
boolean checkForCircularImports) {
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate 类是它的 ImportSelector-> 委托,用于确定导入
// EnableDiscoveryClientImportSelector、AutoConfigurationImportSelector
Class> candidateClass = candidate.loadClass();
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
Predicate selectorFilter = selector.getExclusionFilter();
if (selectorFilter != null) {
exclusionFilter = exclusionFilter.or(selectorFilter);
}
if (selector instanceof DeferredImportSelector) {
// EnableDiscoveryClientImportSelector、AutoConfigurationImportSelector
this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
}
else {
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
Collection importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
}
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate 类是一个 ImportBeanDefinitionRegistry-> 委托给它,用于注册其他 bean 定义
// FeignClientsRegistrar、AutoConfigurationPackages、、、
Class> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 候选类不是ImportSelector 或 ImportBeanDefinitionRegistry-> 将其作为@Configuration类处理
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to process import candidates for configuration class [" +
configClass.getMetadata().getClassName() + "]", ex);
}
finally {
this.importStack.pop();
}
}
}
processImports()方法中会判断如果importCandidates导入候选类实现了ImportBeanDefinitionRegistrar接口,调用解析策略工具类实例化它的子类。并将其添加到ConfigurationClass的importBeanDefinitionRegistrars字段中(Map
1)实例化处理
2)实例化
可见底层调用的是BeanUtils去处理实例化的,之前也讲解了。
3)设置并返回instance
resourceLoader为AnnotationConfigServletWebServerApplicationContext,
environment为StandServletEnvironment
4)填充集合
this.reader.loadBeanDefinitions(configClasses);便是注册@Configuration类型的入口,也是注册ImportBeanDefinitionRegistrar类型入口,可按照之前大的逻辑不难发现会走到ConfigurationClassBeanDefinitionReader#loadBeanDefinitions()方法,将上面解析的configurationClasses集合传递进来。
public void loadBeanDefinitions(Set configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
for (ConfigurationClass configClass : configurationModel) {
// 999520
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
遍历读取 configurationModel,根据其内容向注册中心注册 bean 定义
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 注册BeanDefinition
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// MyBatisPlus拦截器走这里注册定义、NacosServiceAutoConfiguration、NacosDiscoveryAutoConfiguration、
// NacosServiceRegistryAutoConfiguration ->nacosServiceRegistry、nacosRegistration、nacosAutoServiceRegistration、
loadBeanDefinitionsForBeanMethod(beanMethod);
}
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 如:EnableConfigurationPropertiesRegistrar
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
这里的逻辑之前走了一部分,这次会走底部的loadBeanDefinitionsFromRegistrars()逻辑,从入参就可以略知一二了。
注意:configClass是启动类。
private void loadBeanDefinitionsFromRegistrars(Map registrars) {
registrars.forEach((registrar, metadata) ->
registrar.registerBeanDefinitions(metadata, this.registry,
this.importBeanNameGenerator));
}
这里遍历registrars所有登记员,然后调用具体登记员的批量登记方法,详细逻辑后面分析。
default void registerBeanDefinitions(AutoProxyRegistrar.AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry,
BeanNameGenerator importBeanNameGenerator) {
registerBeanDefinitions(importingClassMetadata, registry);
}
进入到这里后,委托registerBeanDefinitions(importingClassMetadata, registry)处理。从步骤3中可见它会交由它的实现类FeignClientRegistrar去处理相应的细节,具体下一篇文章会分析。