概述
ConfigurationClassPostProcessor
位于 org.springframework.context.annotation
包中,这是一个 BeanDefinitionRegistryPostProcessor,隐含地也实现了接口BeanFactoryPostProcessor,用于 spring
应用启动过程中 @Configuration
类的处理 : 发现和处理所有的配置类,注册其中的bean
定义。
继承关系
关于应用
1. 何时被引入
-
非
Springboot
的Sping
应用,当在配置文件中使用<context:annotation-config/>
或者<context:component-scan/>
时,该BeanFactoryPostProcessor
会被注册。 -
Springboot
应用中在ApplicationContext
对象创建时,会在应用上下文类(参考AnnotationConfigServletWebServerApplicationContext
/AnnotationConfigReactiveWebServerApplicationContext
)的构造函数中创建AnnotatedBeanDefinitionReader
对象时调用AnnotationConfigUtils.registerAnnotationConfigProcessors()
注册这个BeanFactoryPostProcessor
到容器。
// AnnotationConfigUtils#registerAnnotationConfigProcessors 代码片段
// 这里 CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME 值为 :
// org.springframework.context.annotation.internalConfigurationAnnotationProcessor
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
2. 何时被使用
ConfigurationClassPostProcessor
既实现了BeanDefinitionRegistryPostProcessor
定义的方法postProcessBeanDefinitionRegistry
,也实现了接口BeanFactoryPostProcessor
定义的方法postProcessBeanFactory
。
AbstractApplicationContext.refresh()
方法执行时,在BeanFactory
,也就是Spring
容器被准备(prepare
)和postProcess
之后,AbstractApplicationContext
的invokeBeanFactoryPostProcessors()
方法被调用,这个方法用来执行所有容器中被作为bean
注册的BeanFactoryPostProcessor
,其中就包括对ConfigurationClassPostProcessor
方法postProcessBeanDefinitionRegistry()
以及postProcessBeanFactory()
方法的调用。
// 调用链
AbstractApplicationContext.refresh()
=> invokeBeanFactoryPostProcessors()
=> PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors()
方法会先应用所有的BeanDefinitionRegistryPostProcessor
的方法postProcessBeanDefinitionRegistry()
,直到参数指定的或者容器中所有的这些BeanDefinitionRegistryPostProcessor
的该方法都被执行完,然后执行所有的BeanFactoryPostProcessor
的方法postProcessBeanFactory()
直到参数指定的或者容器中所有的这些BeanFactoryPostProcessor
的该方法都被执行完。
这里之所有这样做的原因是上述方法执行时有可能注册新的
BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor
到容器,而这些新注册的BeanDefinitionRegistryPostProcessor/BeanFactoryPostProcessor
也需要在这个阶段执行。
另外需要注意 :
-
BeanDefinitionRegistryPostProcessor
可能会注册另外一个BeanDefinitionRegistryPostProcessor
。 -
一个非
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
可能会注册另外一个BeanFactoryPostProcessor
。 -
一个非
BeanDefinitionRegistryPostProcessor
BeanFactoryPostProcessor
不会注册另外一个BeanDefinitionRegistryPostProcessor
(注册了但是不会被执行)。
因为配置类中定义的每个bean
定义方法都必须要赶在其它BeanFactoryPostProcessor
应用前,所以完成bean
定义注册任务的ConfigurationClassPostProcessor
被设计为拥有最高执行优先级Ordered.HIGHEST_PRECEDENCE
。
源代码分析
1.postProcessBeanDefinitionRegistry()
使用工具ConfigurationClassParser
尝试发现所有的配置(@Configuration
)类,使用工具ConfigurationClassBeanDefinitionReader
注册所发现的配置类中所有的bean
定义。结束执行的条件是所有配置类都被发现和处理,相应的bean
定义注册到容器。
/**
* Derive further bean definitions from the configuration classes in the registry.
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already " +
"called on this post-processor against " + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against "
+ registry);
}
this.registriesPostProcessed.add(registryId);
processConfigBeanDefinitions(registry);
}
/**
* Build and validate a configuration model based on the registry of
* Configuration classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 用来记录候选配置类
List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
// 将容器中已经登记的Bean定义作为候选配置类名称 , 举例如下 :
// candidateNames = {String[8]@3533}
// 0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"
// 1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"
// 2 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"
// 3 = "org.springframework.context.annotation.internalPersistenceAnnotationProcessor"
// 4 = "org.springframework.context.event.internalEventListenerProcessor"
// 5 = "org.springframework.context.event.internalEventListenerFactory"
// 6 = "application" ⇐ 这是开发人员使用了注解 @SpringBootApplication 的程序入口类
// 7 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"
String[] candidateNames = registry.getBeanDefinitionNames();
// 程序此时处于容器启动的早期, 通常此时 candidateNames 中实际上只会有一个配置类,
// 在上例中就是 application
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed "+
"as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef,
this.metadataReaderFactory)) {
// 如果这个Bean定义有注解@Configuration,将其记录为候选配置类
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
// 一个候选配置类都没有找到,直接返回
return;
}
// Sort by previously determined @Order value, if applicable
Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
@Override
public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
}
});
// Detect any custom bean name generation strategy supplied through the
// enclosing application context
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet &&
sbr.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
BeanNameGenerator generator = (BeanNameGenerator)
sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
// Parse each @Configuration class,现在准备要分析配置类了
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
// 表示将要被处理的候选配置类
// 因为不清楚候选是否确实是配置类,所以使用BeanDefinitionHolder类型记录
// 这里初始化为方法开始时容器中注解了@Configuration的Bean定义的集合
Set<BeanDefinitionHolder> candidates =
new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
// 表示已经处理的配置类,已经被处理的配置类已经明确了其类型,所以用 ConfigurationClass 类型记录,
// 这里初始化为空
Set<ConfigurationClass> alreadyParsed =
new HashSet<ConfigurationClass>(configCandidates.size());
do {
// 分析配置类,分析过程中
// 1. 如果遇到注解了@Component类,直接作为Bean定义注册到容器
// 2. 如果注解或者注解的注解中有@Import, 处理所有这些@import,识别配置类,
// 添加到分析器的属性configurationClasses中去
parser.parse(candidates);
parser.validate();
// 从分析器parser中获取分析得到的配置类configurationClasses
Set<ConfigurationClass> configClasses =
new LinkedHashSet<ConfigurationClass>(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());
}
// 使用 ConfigurationClassBeanDefinitionReader reader 从 configClasses 中加载
// Bean定义并注册到容器
this.reader.loadBeanDefinitions(configClasses);
// 刚刚处理完的配置类记录到已处理配置类alreadyParsed
alreadyParsed.addAll(configClasses);
// 清空候选配置类集合,为下一轮do循环做初始化准备
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
// 经过一轮do循环,现在容器中Bean定义数量超过了该次循环开始时的容器内Bean定义数量,
// 说明在该次循环中发现并注册了更多的Bean定义到容器中去,这些新注册的Bean定义
// 也有可能是候选配置类,它们也要被处理用来发现和注册Bean定义
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames =
new HashSet<String>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<String>();
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())) {
// 在新注册的Bean定义中找到一个候选配置类
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());// 一直循环到没有新的候选配置类被发现
// Register the ImportRegistry as a bean in order to support ImportAware
// @Configuration classes
if (sbr != null) {
if (!sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
2. postProcessBeanFactory()
postProcessBeanFactory()
的主要目的有两个:
- 对容器中的每个配置类做增强;
- 往容器中增加一个
BeanPostProcessor
:ImportAwareBeanPostProcessor
(如果所增加的BeanPostProcessor
已经存在会先将其删除然后重新添加)
/**
* Prepare the Configuration classes for servicing bean requests at runtime
* by replacing them with CGLIB-enhanced subclasses.
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// 因为同一个ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry
// 总是先于它的postProcessBeanFactory被调用,因此代码应该不会执行到这里,所以这里再次调用
// 应该是一次确保
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 对容器中的每个配置类做增强
enhanceConfigurationClasses(beanFactory);
// 往容器中增加一个ImportAwareBeanPostProcessor(如果所增加组件已经存在会先将其删除然后重新添加)
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
2.1 使用ConfigurationClassEnhancer
增强每个配置类
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// 从容器中找到所有配置类的bean定义
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException(
"Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '"
+ beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
if (configBeanDefs.isEmpty()) {
// nothing to enhance -> return immediately
return;
}
// 对每个配置类进行增强
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
// If a @Configuration class gets proxied, always proxy the target class
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
Class<?> enhancedClass = enhancer.enhance(configClass,
this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(
String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(),
enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
2.2 添加ImportAwareBeanPostProcessor
到容器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
相关资料
- 缺省配置Springboot Web应用启动过程中Bean的登记
- ConfigurationClassPostProcessor 官方文档
- AbstractApplicationContext.invokeBeanFactoryPostProcessors()
- PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()
- Spring 工具类 ConfigurationClassParser 分析得到配置类
- Spring 工具类 ConfigurationClassBeanDefinitionReader 注册配置类中的bean定义
- Spring 工具类 ConfigurationClassEnhancer