Spring版本:
<version>5.2.1.RELEASE</version>
上一篇:10-Spring容器創建之refresh(4)——invokeBeanFactoryPostProcessors(1)
上一篇還遺留了兩個問題,這兩個問題非常重要
-
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
(PriorityOrdered
) 2-3節介紹ConfigurationClassPostProcessor
類如何解析@Configuration
註解類
-
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
4節介紹ConfigurationClassPostProcessor
類如何增強配置類
那麼下面我們就一步一步看它是如何做這兩件事情的。這裏有必要提到一個非常重要的類了:ConfigurationClassPostProcessor
。
1. ConfigurationClassPostProcessor
的類結構
想要了解一個類,那當然首當其衝應該看它所實現的接口和父類:
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware
接着爲了更只管的看到這些類,我們來看看這些類的類結構吧
接下來,我們就要進入上一篇遺留下來的第一個問題了。看一下invokeBeanFactoryPostProcessors
在調用 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
(PriorityOrdered
)時所作的工作!
2. invokeBeanDefinitionRegistryPostProcessors
方法
private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}
從上一篇文章中,我們可以知道,進入這個方法的postProcessors
只有一個,即ConfigurationClassPostProcessor
類型的Bean
。因此在上面代碼中執行postProcessor.postProcessBeanDefinitionRegistry(registry);
時,會走到ConfigurationClassPostProcessor
類的postProcessBeanDefinitionRegistry
方法中。我們進入該方法。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
// 給registry生成一個全局唯一ID。防止重複
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);
// 進行BeanDefinition的加載。
// 3.節 具體介紹
processConfigBeanDefinitions(registry);
}
3. processConfigBeanDefinitions
方法
下面我們就開始對傳入的配置類進行註解解析了。這裏的配置類即:啓動項目的時候傳入的類:
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig_AOP.class);
從上述代碼可以看出本項目中的配置類爲:MainConfig_AOP
。
我們回來繼續分析processConfigBeanDefinitions
的實現方式
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 獲取已經註冊到beanFactory中的beanDefinition。
// 當前有以下6個(5個內置類+1個配置類),具體參見上篇文章1.節
// internalConfigurationAnnotationProcessor
// internalAutowiredAnnotationProcessor
// internalCommonAnnotationProcessor
// internalEventListenerProcessor
// internalEventListenerFactory
// mainConfig_AOP
String[] candidateNames = registry.getBeanDefinitionNames();
//-------------------------------------------【功能一】-------------------------------------------
// 找到上面6個BeanDenition中是帶有@Configuration的類, 實際就是找出internalConfigurationAnnotationProcessor
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
// 檢查是否是@Configuration的類,如果是就將其放入到configCandidates變量中。
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 如果沒有@Configuration的類,直接返回
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
// @Configuration的類是可以有順序的,按照順序進行排序
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// 我們可以更改scan和import的方式,如果沒有更改默認爲:掃描爲首字母小寫,import爲全類名
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 的類
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
// 裝載已經處理過的配置類,最大長度爲:configCandidates.size()
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 核心方法 : 解析配置類,找到配置類中的@Bean @Import @Scan類信息
// 將這些信息放入到ConfigurationClass中
// -----【1】----- 3.1節 具體介紹
parser.parse(candidates);
// 校驗,配置類不能是final類型的,因爲在後面需要使用CGLIB生成代理類
parser.validate();
// 得到所有已經需要解析的類,【1】中會給出圖片
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());
}
//-------------------------------------------【功能三】-------------------------------------------
// 核心方法 : 將配置類中的@Bean @Import @Scan類信息註冊爲BeanDefinition
// -----【2】----- 3.2節 具體介紹
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
// 如果registry中註冊的bean的數量 大於 之前獲得的數量,
// 則意味着在解析的類中還引入類其他的註解類,那麼就需要對新引入的類進行解析
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
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();
}
}
根據以上代碼,可以知道上述代碼實現了三個功能:
- 【功能一】
- 從6個
BeanDenition
中找到中是帶有@Configuration
類的BeanDefinition
- 從6個
- 【功能二】
- 通過執行
parser.parse(candidates);
解析配置類,即將配置類中標註@Bean
、@Import
等的類找出來
- 通過執行
- 【功能三】
- 通過執行
this.reader.loadBeanDefinitions(configClasses);
將功能二中找到的註解類轉換爲BeanDefinition
,並將其註冊到beanFactory
中
- 通過執行
3.1. parser.parse(candidates)
解析配置類
public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 由於當前是使用註解驅動,因此當前配置類屬於AnnotatedBeanDefinition
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);
}
}
this.deferredImportSelectorHandler.process();
}
由於當前項目使用的是註解驅動,所以進入AnnotatedBeanDefinition
下面的parse
方法。這個方法體如下:
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName));
}
它會將傳入的metadata
和beanName
封裝成ConfigurationClass
,然後將封裝好後的ConfigurationClass
作爲參數傳入processConfigurationClass
中。那麼我們繼續看processConfigurationClass
方法做了哪些操作。
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
return;
}
// 如果這個配置類已經存在了,後面又被@Import進來了,會做屬性合併
ConfigurationClass existingClass = this.configurationClasses.get(configClass);
if (existingClass != null) {
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);
}
}
// Recursively process the configuration class and its superclass hierarchy.
SourceClass sourceClass = asSourceClass(configClass);
do {
//-------------------------------------------【功能一】-------------------------------------------
// -----【1】----- 這個方法是核心方法 3.1.1 中詳細介紹
// 解析配置類
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
}
while (sourceClass != null);
//-------------------------------------------【功能二】-------------------------------------------
this.configurationClasses.put(configClass, configClass);
}
以上方法做了兩個事情:
-
【功能一】
sourceClass = doProcessConfigurationClass(configClass, sourceClass);
-> 3.1.1 具體介紹- 解析配置類
- 並將解析的結果放到
configClass
中保存
-
【功能二】
this.configurationClasses.put(configClass, configClass);
-> 3.1.2 具體介紹- 將解析之後的結果放到一個
LinkedHashMap
中保存
- 將解析之後的結果放到一個
3.1.1 sourceClass = doProcessConfigurationClass(configClass, sourceClass);
解析配置類
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// 查看內部類
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 先遞歸地處理內部類, 本項目沒有增加內部類,因此暫時先不分析這一塊的內容,後續再增加
processMemberClasses(configClass, sourceClass);
}
// 處理每個 @PropertySource 註解
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 註解
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) {
// 配置類中註解了@ComponentScan, 因此現在立刻執行掃描,獲取其中的BeanDefinition
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// 對ComponentScan得到的BeanDefinition進行檢查,看裏面是否有需要處理的配置類,有的話進行處理
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
// 處理每個 @Import 註解,將這個註解的類放到configClass的importBeanDefinitionRegistrars中
// 先調用 getImports(),獲取sourceClass上所有@Import註解的value
processImports(configClass, sourceClass, getImports(sourceClass), true);
// 處理每個 @ImportResource 註解
// 本項目中因爲使用的是AOP的例子,因此有一個@Import,
// 即在處理@EnableAspectJAutoProxy註解的時候,引入的@Import(AspectJAutoProxyRegistrar.class)
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 註解
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}
// Process default methods on interfaces
processInterfaces(configClass, sourceClass);
// 處理父類
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;
}
以上代碼顯示ConfigurationClassParser
類的doProcessConfigurationClass
方法主要做的事情。按照順序依次爲:
- [1] 內部配置類:找到配置類中的內部配置類,若有內部配置類,對內部配置類進行遞歸解析
- [2]
@PropertySource
:這個暫時我還沒有用到,以後用到再補充 - [3]
@ComponentScan
:這裏掃描到的Bean
,就直接register註冊了!!所以在@ComponentScan
註解中的類的註冊時機是非常早的!要早於其他的註解所標註的類。(通過ClassPathBeanDefinitionScanner
去的doScan
方法去掃描註冊!!) - [4]
@Import
:分三種情況:- 【情況一】:普通類 放到
ConfigurationClass
中保存 - 【情況二】:實現了
ImportSelector
:放在ConfigurationClass
中保存。若實現DeferredImportSelector
會在ConfigurationClass
的deferredImportSelectorHandler
屬性保存 - 【情況三】:實現了
ImportBeanDefinitionRegistrar
,放在ConfigurationClass
類的importBeanDefinitionRegistrars
屬性中。(AOP
的AspectJAutoProxyRegistrar
就屬於這一類)
- 【情況一】:普通類 放到
- [5]
@ImportResource
:導入XML
文件。放在ConfigurationClass
類的importedResources
屬性中 - [6]
@Bean
:配置類的方法上標註@Bean
的方法。放在ConfigurationClass
類的beanMethods
屬性中- 本文中在配置文件中寫了2個
Bean
註解,因此在執行完這個方法的時候,可以看到ConfigurationClass
類的beanMethods
屬性中有2個類。
- 本文中在配置文件中寫了2個
@Configuration
@EnableAspectJAutoProxy
public class MainConfig_AOP {
@Bean
public MathCalculator calculator() {
return new MathCalculator();
}
@Bean
public LogAspects logAspects() {
return new LogAspects();
}
}
- [7]
processInterfaces
:處理配置類的接口的default
方法 - [8] 處理父類:如果父類也是配置文件,則繼續處理,直到父類全部處理完
- [9]
return null
:全部處理完成後,返回null
執行到這裏,我們得到了項目中完整的ConfigurationClass
,它的beanNames
爲配置類的名字,它有兩個beanMethods
, 有一個importBeanDefinitionRegistrars
(因爲當前項目的例子是AOP的例子)。現在我們可以回溯到3.節中,我們已經執行完了3.節的【功能二】部分,下面我們繼續來看3. 節【功能三】是如何實現的。
3.2 this.reader.loadBeanDefinitions(configClasses)
將註解轉變爲beanDefinition
執行到這裏,我們已經拿到了ConfigurationClass
,它裏面包含了配置類的所有解析註解內容,但是還沒有把這些信息註冊到beanFactory
,這一步我們就是將configClasses
中的信息轉變爲beanDefintiion
,然後放到beanFacttory
中。現在我們先看看目前位置beanFacttory
中的beanDefintiion
都有什麼。
還是之前的那些beanDefintiion
。注意:如果我們在配置類中有@Import
註解,那麼此時:beanDefintiion
中還會有@Import
註解對應的beanDefintiion
(原因在3.1節有介紹)。我們繼續向下分析。
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
// 找到項目中所有@Configuration註解標註的類
for (ConfigurationClass configClass : configurationModel) {
// 根據ConfigurationClass來註冊BeanDefinition
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
接下來我們看一下它是如何通過ConfigurationClas
來註冊BeanDefinition
的吧
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;
}
if (configClass.isImported()) {
// 處理@Import的配置類
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
// 這裏處理配置類中使用@Bean的方法對應的類
// 執行完這一步,當前的項目中的beanFactory的多了
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// 註冊@ImportResource進來的Bean
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 註冊ImportBeanDefinitionRegistrar類型的
// 這裏非常重要,AOP的實現全靠它了!!!這裏會創建AnnotationAwareAspectJAutoProxyCreator
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
執行完loadBeanDefinitionsForBeanMethod(beanMethod);
後,beanFactory
中的BeanDefinitions
增加了2個:
執行完loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
後,beanFactory
中的BeanDefinitions
增加了1個(與AOP
有關的AnnotationAwareAspectJAutoProxyCreator
)
至此,我們已經將本篇中的第一個問題解決完了。 下面我們解決第二個問題
4. invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
這個功能實際上是利用CGLIB
來增強我們的配置類,會爲Spring添加一個後置處理器:ImportAwareBeanPostProcessor
。
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
// 實際上這裏的postProcessors只有一個,即ConfigurationClassPostProcessor
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanFactory(beanFactory);
}
}
我們進入ConfigurationClassPostProcessor
類的postProcessBeanFactory
方法
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)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 該方法的核心方法,在4.1節下面會重點介紹
enhanceConfigurationClasses(beanFactory);
// 增加後置處理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
4.1 enhanceConfigurationClasses
增強配置類
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
// 拿到所有的BeanDefinition(6個內置+1個配置類+2個配置類@Bean引入的類+1個與AOP有關的類),
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// configClassAttr 拿到的是配置類
Object configClassAttr = beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE);
MethodMetadata methodMetadata = null;
if (beanDef instanceof AnnotatedBeanDefinition) {
methodMetadata = ((AnnotatedBeanDefinition) beanDef).getFactoryMethodMetadata();
}
if ((configClassAttr != null || methodMetadata != null) && beanDef instanceof AbstractBeanDefinition) {
// Configuration class (full or lite) or a configuration-derived @Bean method
// -> resolve bean class at this point...
AbstractBeanDefinition abd = (AbstractBeanDefinition) beanDef;
if (!abd.hasBeanClass()) {
try {
abd.resolveBeanClass(this.beanClassLoader);
}
catch (Throwable ex) {
throw new IllegalStateException(
"Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
// 這裏判斷是否是full類型的Configuration.
// full:指 @Configuration 註解的類,說明是一個完全(full)配置類
// 若類上只有 @Component,@ComponentScan,@Import 等說明是一個簡化(life)配置類
if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
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'.");
}
// 將配置類的beanName和配置類的beanDefinition放到configBeanDefs變量中
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);
// Set enhanced subclass of the user-specified bean class
Class<?> configClass = beanDef.getBeanClass();
// 對配置類進行CGLIB增強
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()));
}
// 把增強後的配置類放回去覆蓋原來的
// 因此,以後我們在通過Spring的上下文getBean()到的配置類都不是原始的配置類了,而是增強後的配置類
beanDef.setBeanClass(enhancedClass);
}
}
}
5. 總結
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
的功能有三個- 【功能一】找到解析配置類的類:
internalConfigurationAnnotationProcessor
- 【功能二】利用
internalConfigurationAnnotationProcessor
解析配置類 ,將配置類中的@Import
、@ComponentScan
、@Bean
等解析出來放入到ConfigurationClas
的屬性中 - 【功能三】將
ConfigurationClas
的屬性中對應的類轉換爲BeanDefinition
,然後註冊到beanFactiory
中
- 【功能一】找到解析配置類的類:
以上我們完成了invokeBeanFactoryPostProcessors
功能的分析,下一篇我們繼續分析refresh
方法中的第六個方法registerBeanPostProcessors
方法。