11-Spring容器創建之refresh(4)——invokeBeanFactoryPostProcessors(2)

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
  • 【功能二】
    • 通過執行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));
	}

它會將傳入的metadatabeanName封裝成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會在ConfigurationClassdeferredImportSelectorHandler屬性保存
    • 【情況三】:實現了ImportBeanDefinitionRegistrar,放在ConfigurationClass類的importBeanDefinitionRegistrars屬性中。(AOPAspectJAutoProxyRegistrar就屬於這一類)

在這裏插入圖片描述

  • [5] @ImportResource:導入XML文件。放在ConfigurationClass類的importedResources屬性中
  • [6] @Bean:配置類的方法上標註@Bean的方法。放在ConfigurationClass類的beanMethods屬性中
    • 本文中在配置文件中寫了2個Bean註解,因此在執行完這個方法的時候,可以看到ConfigurationClass類的beanMethods屬性中有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方法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章