spring 的 ConfigurationClassPostProcessor
主要是解析@Configuration
類,通常只有一個入口類,對他進行遞迴解析,解析完所有關聯類,包括使用 Configuration、Component、ComponentScan、Import、ImportResource、Bean
註解關聯的類,將其註冊進BeanFactory
中。
ConfigurationClassPostProcessor
類的結構圖如下:
在建立容器SpringApplication#createApplicationContext
時將ConfigurationClassPostProcessor
註冊進 ApplicationContext
中。
他實現了 BeanDefinitionRegistryPostProcessor
,將在 AbstractApplicationContext#refresh
中將在 BeanFactory
準備好之後執行。
/**
* Derive further bean definitions from the configuration classes in the registry.
* 從派生類中註冊更多的bean
*/
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 生成ID,如果包含則說明該BeanFactoryProcess已經執行過 postProcessBeanDefinitionRegistry 方法,不能重複處理
int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
}
// 生成ID,如果包含則說明該BeanFactoryProcess已經執行過 postProcessBeanFactory 方法,不能重複處理
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + registry);
}
// 記錄已經執行過 postProcessBeanDefinitionRegistry 方法
this.registriesPostProcessed.add(registryId);
// 驗證和註冊BeanDefinitions
processConfigBeanDefinitions(registry);
}
processConfigBeanDefinitions
邏輯主要是對配置類進行分析,如果掃描到該配置類使用了Configuration、Component、ComponentScan、Import、ImportResource、Bean
註解,則認為是配置類。
- 在解析時,判斷是否解析過,已經被解析過不會再次解析,如果已經解析過,會對其表示,根據
Configuration#proxyBeanMethods
的值進行標記: true將其標識為full
,false 標識為lite
。 - 有需要進行解析的配置類,則會根據 order 進行排列解析順序。
- 使用
ConfigurationClassParser
對其進行解析,將解析到的配置類返回,使用ConfigurationClassBeanDefinitionReader
進行註冊BeanDefinition
。 - 一直按照步驟3進行,直到解析完所有的配置類。
/**
* 1. 掃描入口類,在
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
// 檢查 bean class 是否使用Configuration、Component、ComponentScan、Import、ImportResource、Bean 註解。
// 如果使用了,則將 beanDef 進行標識(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE)。
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
// beanDef 是否包含該屬性,包含則說明處理過
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
// 新增需要解析的配置類
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 沒有配置類,則直接返回
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
// 根據order進行排序,從小到大,order越小越前
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
// 設定 bean 名稱生成器
SingletonBeanRegistry sbr = null;
if (registry instanceof SingletonBeanRegistry) {
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 解析配置類 (@configuration)
// 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 {
// 解析
parser.parse(candidates);
// 驗證:必須可以重寫,不能是final
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());
}
// 向BeanFactory中註冊beanDefinition
this.reader.loadBeanDefinitions(configClasses);
// 新增已經解析的類
alreadyParsed.addAll(configClasses);
// 解析完後清空
candidates.clear();
// 將本次解析出來的配置類存入 candidates 中,以供下一次迴圈進行解析。
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());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
// 新增 ImportRegistry
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
// 清除快取
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
在整個解析過程中,ConfigurationClassParser
和 ConfigurationClassBeanDefinitionReader
起著關鍵作用。
ConfigurationClassParser
解析配置類,會將掃描到的ConfigurationClass
返回,交由ConfigurationClassBeanDefinitionReader
進行註冊。
在 ConfigurationClassParser
解析過程中,如果碰到 @Component、 @bean、@Import
等註解定義的類,將會委託給對應的處理器進行處理,這些類的處理方式與處理 @Configuration
註解定義的類不一樣,在處理過程中就會將 BeanDefinition
註冊進BeanFactory
。
ConfigurationClassParser#parse()
方法分析
parse方法內部呼叫的是 ConfigurationClassParser#processConfigurationClass
來進行解析
/**
* 傳入需要解析的配置類
*/
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 判斷型別,各個分支最後都是呼叫 processConfigurationClass()
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
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);
}
}
// 匯入使用 ImportSelector註解 的配置類
this.deferredImportSelectorHandler.process();
}
processConfigurationClass() 分析
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
// 是否跳過:解析 Conditional 條件
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
// class 解析記錄已經存在,將其合併
if (configClass.isImported()) {
if (existingClass.isImported()) {
existingClass.mergeImportedBy(configClass);
}
// Otherwise ignore new imported config class; existing non-imported class overrides it.
return;
}
else {
// Explicit bean definition found, probably replacing an import.
// Let's remove the old one and go with the new one.
this.configurationClasses.remove(configClass);
this.knownSuperclasses.values().removeIf(configClass::equals);
}
}
// 從當前類開始,遞迴向上透過doProcessConfigurationClass方法處理父類,直到是由java提供父類或已經處理過為止。
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
// 記錄該類已經處理過。
this.configurationClasses.put(configClass, configClass);
}
doProcessConfigurationClass
處理流程:
- 首先處理配置類的內部類
- 處理配置類上的
@PropertySource
註解 - 處理配置類上的
@ComponentScan
註解 - 處理配置類上的
@Import
註解 - 處理配置類上的
@ImportResource
註解 - 處理在配置類中使用到的
@Bean
的註解方法 - 處理配置類的介面預設方法
- 返回滿足要求的父類,如果父類不需要處理或已經處理過,返回null,表示這個配置類已經處理完成
protected final SourceClass doProcessConfigurationClass(
ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
throws IOException {
// @Configuration 組合了 @Component,所以使用了 @Configuration 會進入該方法,對內部類進行遞迴掃描
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// Recursively process any member (nested) classes first
processMemberClasses(configClass, sourceClass, filter);
}
// 處理 @PropertySource 註解,將 @PropertySource 指定的類建立並加入到 environment 中。
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 處理配置類上的 @ComponentScan 註解,委託給 componentScanParser 處理
// 使用 ComponentScanAnnotationParser 掃描在配置類上使用到的 @ComponentScan 指定的包
// 將發現的類的BeanDefinition註冊到 BeanFactory 中。
// 之後在判斷這些類是否是配置類,如果是,則對其進行遞迴掃描。
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
// 判斷這些類是否是配置類,如果是,則對其進行遞迴掃描:執行 processConfigurationClass
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 處理 @Import 註解
// 如果@Import指定的類實現了 ImportSelector 介面,使用 deferredImportSelectorHandler 進行處理
// 如果實現了 ImportBeanDefinitionRegistrar 介面,則將其記錄到 importBeanDefinitionRegistrars 集合中,在執行完該方法後進行處理。
// 如果不是 ImportSelector或 ImportBeanDefinitionRegistrar 的實現類,則對指定的類執行 processConfigurationClass 方法,進行解析。
// Process any @Import annotations
processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
// 處理 @ImportResource ,將其記錄到 importedResources 集合中,供後面處理
// Process any @ImportResource annotations
AnnotationAttributes importResource =
AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
if (importResource != null) {
String[] resources = importResource.getStringArray("locations");
Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
for (String resource : resources) {
String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
configClass.addImportedResource(resolvedResource, readerClass);
}
}
// 處理配置類中使用 @Bean 的方法,找到所有用 @bean 註解的方法,儲存進 beanMethods 中,供後面處理
// Process individual @Bean methods
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// 處理介面預設方法
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// 解析超類,如果超類不是 java 開頭並且未處理過,返回null
// Process superclass, if any
if (sourceClass.getMetadata().hasSuperClass()) {
String superclass = sourceClass.getMetadata().getSuperClassName();
if (superclass != null && !superclass.startsWith("java") &&
!this.knownSuperclasses.containsKey(superclass)) {
this.knownSuperclasses.put(superclass, configClass);
// Superclass found, return its annotation metadata and recurse
return sourceClass.getSuperClass();
}
}
// No superclass -> processing is complete
return null;
}