ConfigurationClassPostProcessor 是spring框架中提供解析配置类的一个比较重要的后置处理器,其主要作用是解析配置类,即@Configuration标记的类
- 其实现了BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor:
在容器BeanFactory创建好并加载了已经配置(比如配置文件)的bean定义后,会执行 postProcessBeanDefinitionRegistry 方法和 postProcessBeanFactory 方法;
ConfigurationClassPostProcessor#processConfigBeanDefinitions
- postProcessBeanDefinitionRegistry 方法里解析BeanDefinition逻辑主要是processConfigBeanDefinitions完成的
方法签名:org.springframework.context.annotation.ConfigurationClassPostProcessor#processConfigBeanDefinitions
下面方法只保留了核心方法
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
... 省略部分代码...
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
//@A
parser.parse(candidates);
parser.validate();
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//@B
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
... 省略部分代码...
}
ConfigurationClassParser#parse
上面标记@A的代码:其主要逻辑是委托ConfigurationClassParser类来完成;
这个工具类自身的逻辑并不注册bean定义,它的主要任务是发现@Configuration注解的所有配置类并将这些配置类交给调用者(调用者会通过其他方式注册其中的bean定义);而对于非@Configuration注解的其他bean定义,比如@Component注解的bean定义,该工具类使用另外一个工具ComponentScanAnnotationParser扫描和注册它们。
以下是配置类【Configuration标记的类】流程控制核心方法:
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
//@AA
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//@BB
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
//@CC
this.deferredImportSelectorHandler.process();
}
//@AA:解析配置,内部会发生方法递归调用解析(主要发生在ComponentScan扫描出来的候选类,会被一一递归解析),最终是将解析到的类放到 this.configurationClasses 属性
//@BB:和 @AA逻辑一致
//@CC:在@AA 和@BB循环完毕后,会解析被@import的类,但是有个特殊的接口不会在@AA 和@BB中被处理,那就是DeferredImportSelector,嘿嘿 spring boot 中的 AutoConfigurationImportSelector就是一个DeferredImportSelector实现类;DeferredImportSelector 的设计目的是在所有其他的配置类被处理后才处理。