天天看點

Spring-BeanFactory後置處理器之ConfigurationClassPostProcessor本文能幫你解答的問題類介紹方法源碼解讀總結

目錄

本文能幫你解答的問題

類介紹

作用

類繼承關系

Aware

Ordered

BeanDefinitionRegistryPostProcessor

BeanFactoryPostProcessor

添加ConfigurationClassPostProcessor的政策

方法源碼解讀

postProcessBeanDefinitionRegistry

step1. 尋找所有配置類的BeanDefinition

step2. 排序配置類

step3. 解析配置類及部分beanDefinition的注冊

step4. 完成@Bean、@Import等bean的解析與注冊

postProcessBeanFactory

CGLIB增強Configuration類

添加ImportAwareBeanPostProcessor

總結

關于-BeanFactory後置處理器介紹見:Spring拓展機制之BeanFactoryPostProcessor

本文能幫你解答的問題

  1. ConfigurationClassPostProcessor的作用是什麼?
  2. @Configuration、@Component、@ComponentScan、@ComponentScans、@Bean、@Import等注解是如何完成bean注冊的?
  3. @Conditional注解如何控制配置類是否需要解析?
  4. @Configuration的bean為什麼要增強?增強了什麼邏輯?

類介紹

作用

非常重要的一個BeanFactory後置處理器,通過掃描配置類完成各種注解的解析,自動完成所有BeanDefinition的注冊。

例如通過對@ComponentScan、@Bean、@Import等注解的解析完成bean的注冊。

類繼承關系

Spring-BeanFactory後置處理器之ConfigurationClassPostProcessor本文能幫你解答的問題類介紹方法源碼解讀總結

繼承了3個Aware接口、用于控制執行順序的Ordered接口,以及BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor。

Aware

用于拿到ClassLoader、ResourceLoader以及Environment對象。

Ordered

通過實作getOrder控制執行該BeanFactory後置處理器的優先級。

ConfigurationClassPostProcessors實作的getOrder放回的是Integer.MAX_VALUE,用于保證最先執行。

了解BeanFactoryProcessor執行順序的知道,實作了PriorityOrdered的後置處理器會優先于實作了Ordered的後置處理器,是以ConfigurationClassPostProcessors還實作了PriorityOrdered以確定第一個執行。

@Override
	public int getOrder() {
		return Ordered.LOWEST_PRECEDENCE;  // within PriorityOrdered
	}
           

BeanDefinitionRegistryPostProcessor

通過實作postProcessBeanDefinitionRegistry方法,能拿到BeanDefinitionRegistry對象,BeanDefinitionRegistry是注冊、修改BeanDefinition的重要類,是以通實作該方法可以向容器中對BeanDefinition進行自定義新增或者修改等。

BeanFactoryPostProcessor

通過實作postProcessBeanFactory,能拿到BeanFactory對象,是在所有到BeanDefinition注冊完成後,執行個體化前回調,進而可以對bean做進一步的修改

添加ConfigurationClassPostProcessor的政策

當開啟注解掃描bean,spring則會自動添加該BeanFactory後置處理器,來完成自動掃描注冊的bean。

xml的ApplicationContext環境下開啟方式:

<context:annotation-config/>或者<context:component-scan/>
           

對于AnnotationConfigApplicationContext預設會自動添加ConfigurationClassPostProcessor。(通過構造函數最終調用到AnnotationConfigUtils#registerAnnotationConfigProcessors()完成beanDefition添加,在refresh過程完成該bean的注冊)

方法源碼解讀

這裡從實作的postProcessBeanDefinitionRegistry和postProcessBeanFactory按照執行的先後順序進行分析。

其中觸發這兩個方法的時機都是在 AbstractApplicationContext#refresh的invokeBeanFactoryPostProcessors過程觸發。

AbstractApplicationContext#refresh

    -->AbstractApplicationContext#invokeBeanFactoryPostProcessors

        -->PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors(beanFactory,beanFactoryPostProcessors)

postProcessBeanDefinitionRegistry

@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);
	}
           

ConfigurationClassPostProcessor#processConfigBeanDefinitions:

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
        /1. 尋找所有配置類的BeanDefinition
        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);
				}
			}
			//是否是配置類,是則添加到待處理的集合中
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
        //沒有return不處理
		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}
        
        //2. 排序配置類
		// 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);
		});
		
        //省略部分代碼
        
        //準備好配置解析類
		// 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 {
		    //3. 解析配置類
			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());
			}
			//4. 注冊解析到的所有BeanDefinition
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
            
            //省略部分代碼
		}
		while (!candidates.isEmpty());
        
        //省略部分代碼
	}
           

processConfigBeanDefinitions方法較長,這裡拆分幾個過程。

step1. 尋找所有配置類的BeanDefinition

從目前已經注冊的所有BeanDefinition中尋找屬于配置類的BeanDefinition,放到configCandidates,用于後續的處理。

List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
	String[] candidateNames = registry.getBeanDefinitionNames();
		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);
				}
			}
			//如果是配置類,是則放到configCandidates中
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}
           

問題:什麼類才叫配置類?

帶着這個問題看下ConfigurationClassUtils.checkConfigurationClassCandidate方法邏輯。

public static boolean checkConfigurationClassCandidate(
			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {

		String className = beanDef.getBeanClassName();
		if (className == null || beanDef.getFactoryMethodName() != null) {
			return false;
		}
        //取得類上的注解資訊
		AnnotationMetadata metadata;
		if (beanDef instanceof AnnotatedBeanDefinition &&
				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
			// Can reuse the pre-parsed metadata from the given BeanDefinition...
			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();
		}
		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
			// Check already loaded Class if present...
			// since we possibly can't even load the class file for this Class.
			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
			//繼承了這些類的都不是配置類
			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
					EventListenerFactory.class.isAssignableFrom(beanClass)) {
				return false;
			}
			metadata = AnnotationMetadata.introspect(beanClass);
		}
		else {
            //省略部分代碼
		}
        
        //擷取Configuration注解的值資訊
		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
		//如果是@Configuration的bean,則屬于配置類,會設定CONFIGURATION_CLASS_ATTRIBUTE屬性為full。
		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}
		//如果滿足isConfigurationCandidate,也是配置類,設定CONFIGURATION_CLASS_ATTRIBUTE屬性為lite
		else if (config != null || isConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
		}
		else {
		    //都不滿足不是配置類。
			return false;
		}

		// It's a full or lite configuration candidate... Let's determine the order value, if any.
		//設定排序值用于後續對配置類進行排序處理
		Integer order = getOrder(metadata);
		if (order != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
		}

		return true;
	}
	
           

ConfigurationClassUtils#isConfigurationCandidate:

static {
		candidateIndicators.add(Component.class.getName());
		candidateIndicators.add(ComponentScan.class.getName());
		candidateIndicators.add(Import.class.getName());
		candidateIndicators.add(ImportResource.class.getName());
	}
	
	
    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
		// Any of the typical annotations found?
		//隻要存在上面4種注解中的一種都是配置類
		for (String indicator : candidateIndicators) {
			if (metadata.isAnnotated(indicator)) {
				return true;
			}
		}
		// Finally, let's look for @Bean methods...
		return metadata.hasAnnotatedMethods(Bean.class.getName());
	}

           

總結一下配置類的定義:

  1. 有@Configuration注解的類
  2. 有Component、ComponentScan、Import、ImportResource注解的類
  3. 方法上有@Bean注解的類

特别說明:滿足1和滿足2、3對于配置類的beanDefinition的CONFIGURATION_CLASS_ATTRIBUTE值分别設定為full和lite的原因,這個在postProcessBeanFactory方法中會有答案。

step2. 排序配置類

根據@Order标注的順序來排序所有@Configuration标注的BeanDefinition

// 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);
		});
           

step3. 解析配置類及部分beanDefinition的注冊

解析配置類中的各種注解,例如@ComponentScan、@Import、@Bean等,同時完成部分beanDefinition的注冊,類似與@Component注解的bean,@Configration的bean,對于@Import、@Bean指定的bean會在step4完成beanDefinition的注冊。

// 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);
			parser.validate();
		}
		while (!candidates.isEmpty());
           

ConfigurationClassParser.parse調用鍊路:

ConfigurationClassParser#parse()
    ->ConfigurationClassParser#processConfigurationClass
        ->ConfigurationClassParser#doProcessConfigurationClass
           
protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {
        //處理@Conditional注解,條件判斷目前配置類是否需要處理
	    if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}
        //部分代碼省略
		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass);
		do {
		    //解析配置類的關鍵方法
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);
        //緩存起來,這裡得到的configClass就是經過解析後封裝好的ConfigurationClass,用于後續做經一步的處理
		this.configurationClasses.put(configClass, configClass);
	}
           

processConfigurationClass處理邏輯是先判斷目前配置類是否需要解析,如果需要則然後調用doProcessConfigurationClass去做解析。

@Conditional判斷配置類是否需要解析

通過ConditionEvaluator#shouldSkip(),判斷目前配置類是否需要解析,這裡傳入的phase參數為PARSE_CONFIGURATION,代表是解析配置階段。

public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
		//不存在@Conditional注解,無需跳過
		if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
			return false;
		}
		
		//省略部分代碼
		
		//一個配置類可能有很多@Conditional
		List<Condition> conditions = new ArrayList<>();
		for (String[] conditionClasses : getConditionClasses(metadata)) {
			for (String conditionClass : conditionClasses) {
				Condition condition = getCondition(conditionClass, this.context.getClassLoader());
				conditions.add(condition);
			}
		}
        //排序
		AnnotationAwareOrderComparator.sort(conditions);

        //按順序調用matches方法
		for (Condition condition : conditions) {
			ConfigurationPhase requiredPhase = null;
			
			//是否繼承的ConfigurationCondition,是,則取指定的判斷階段
		    if (condition instanceof ConfigurationCondition) {
				requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
			}
			//判斷如果目前處理階段和Condition指定的階段一緻,則調用match方法。
			if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
				return true;
			}
		}

		return false;
	}

           

特别說明:ConditionEvaluator#shouldSkip方法在兩個階段都會調用,一個是配置類的解析階段,一個是bean的注冊階段,如果需要指定隻在某個階段生效,需要實作ConfigurationCondition來指定處理的階段,ConfigurationPhase參數來區分不同的階段,具體使用參考

@PropertySource("classpath:test.properties")

// 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");
		}
	}
           

ConfigurationClassParser#processPropertySource: 

private void processPropertySource(AnnotationAttributes propertySource) throws IOException {
		//配置檔案的名稱
		String name = propertySource.getString("name");
		if (!StringUtils.hasLength(name)) {
			name = null;
		}
		//配置檔案的編碼
		String encoding = propertySource.getString("encoding");
		if (!StringUtils.hasLength(encoding)) {
			encoding = null;
		}
		//配置檔案路徑
		String[] locations = propertySource.getStringArray("value");
		Assert.isTrue(locations.length > 0, "At least one @PropertySource(value) location is required");
		boolean ignoreResourceNotFound = propertySource.getBoolean("ignoreResourceNotFound");

		Class<? extends PropertySourceFactory> factoryClass = propertySource.getClass("factory");
		PropertySourceFactory factory = (factoryClass == PropertySourceFactory.class ?
				DEFAULT_PROPERTY_SOURCE_FACTORY : BeanUtils.instantiateClass(factoryClass));
        //周遊路徑
		for (String location : locations) {
			try {
				String resolvedLocation = this.environment.resolveRequiredPlaceholders(location);
				//加載到配置檔案封裝成Resource
				Resource resource = this.resourceLoader.getResource(resolvedLocation);
				//将封裝成的PropertySource添加到environment的PropertySources中
				addPropertySource(factory.createPropertySource(name, new EncodedResource(resource, encoding)));
			}
			catch (IllegalArgumentException | FileNotFoundException | UnknownHostException ex) {
		        //代碼省略
			}
		}
	}
	
           

@ComponentScan用于指定自動掃描bean的包路徑。

關于該注解的詳細用法參考

// 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 //委托給componentScanParser完成bean的掃描與注冊 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 //周遊所有掃描到的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()); } } } }

主幹邏輯:

  1. 根據包路徑掃描bean并注冊
  2. 如果是配置類,遞歸走配置類的解析,通過反複對配置類解析,最終完成所有掃描到的bean注冊

bean掃描并注冊過程委托給ComponentScanAnnotationParser#parse:

public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
		ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
				componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
        //nameGenerator,用于擷取bean名稱生成器,如果沒有配置,則取Spring預設
		Class<? extends BeanNameGenerator> generatorClass = componentScan.getClass("nameGenerator");
		boolean useInheritedGenerator = (BeanNameGenerator.class == generatorClass);
		scanner.setBeanNameGenerator(useInheritedGenerator ? this.beanNameGenerator :
				BeanUtils.instantiateClass(generatorClass));
        //scopedProxy,作用?
		ScopedProxyMode scopedProxyMode = componentScan.getEnum("scopedProxy");
		if (scopedProxyMode != ScopedProxyMode.DEFAULT) {
			scanner.setScopedProxyMode(scopedProxyMode);
		}
		else {
			Class<? extends ScopeMetadataResolver> resolverClass = componentScan.getClass("scopeResolver");
			scanner.setScopeMetadataResolver(BeanUtils.instantiateClass(resolverClass));
		}
        //resourcePattern,需要掃描包中的那些資源,預設是:**/*.class,即會掃描指定包中所有的class檔案
		scanner.setResourcePattern(componentScan.getString("resourcePattern"));
        //過濾器:用來配置被掃描出來的那些類會被作為元件注冊到容器中
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addIncludeFilter(typeFilter);
			}
		}
		//過濾器,和includeFilters作用剛好相反,用來對掃描的類進行排除的,被排除的類不會被注冊到容器中
		for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
			for (TypeFilter typeFilter : typeFiltersFor(filter)) {
				scanner.addExcludeFilter(typeFilter);
			}
		}
        //是否延遲初始化被注冊的bean
		boolean lazyInit = componentScan.getBoolean("lazyInit");
		if (lazyInit) {
			scanner.getBeanDefinitionDefaults().setLazyInit(true);
		}

        //basePackages:掃描包路徑
		Set<String> basePackages = new LinkedHashSet<>();
		String[] basePackagesArray = componentScan.getStringArray("basePackages");
		for (String pkg : basePackagesArray) {
			String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
					ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
			Collections.addAll(basePackages, tokenized);
		}
		//basePackageClasses:指定一些類,spring容器會掃描這些類所在的包及其子包中的類
		for (Class<?> clazz : componentScan.getClassArray("basePackageClasses")) {
			basePackages.add(ClassUtils.getPackageName(clazz));
		}
		//如果沒有配置,則取配置類所在的包路徑
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(declaringClass));
		}

		scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
			@Override
			protected boolean matchClassName(String className) {
				return declaringClass.equals(className);
			}
		});
		return scanner.doScan(StringUtils.toStringArray(basePackages));
	}
           

該方法主要就是将注解設定的參數封裝到ClassPathBeanDefinitionScanner中,然後進一步委托給ClassPathBeanDefinitionScanner.doScan進行解析。

ClassPathBeanDefinitionScanner.doScan:

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		//周遊包路徑
		for (String basePackage : basePackages) {
		    //掃描到所有的BeanDefinition。
		    //這裡的BeanDefinition隻是一個很原始的BeanDefinition,很多參數需要進一步設定
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			//周遊設定每一個BeanDefinition的參數
			for (BeanDefinition candidate : candidates) {
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				//scope
				candidate.setScope(scopeMetadata.getScopeName());
				//benaName
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				if (candidate instanceof AnnotatedBeanDefinition) {
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					//完成beanDefinition的注冊
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
           

到這裡完成了所有掃描到的beanDefinition的注冊。

解析@Import

用于批量導入指定的bean,例如當某個Bean上沒有@Component注解時,或者隻是指定具體某幾個bean,則可以通過該注解完成指定bean的導入。

@Import除了導入普通的bean外,還可以導入如下幾種bean:

  1. @Configuration标注的類
  2. 繼承了ImportBeanDefinitionRegistrar的類
  3. 繼承了ImportSelector或者DeferredImportSelector的類

具體使用參考

// Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true);

ConfigurationClassParser#processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
        //省略部分代碼
		else {
			this.importStack.push(configClass);
			try {
			    //周遊了有@Import注解的所有類
				for (SourceClass candidate : importCandidates) {
				    //類是否繼承了ImportSelector
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							//遞歸調用processImports方法
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					//是否繼承了ImportBeanDefinitionRegistrar
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();
						ImportBeanDefinitionRegistrar registrar =
								ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					//都不是,則作為配置類進行處理,實際是遞歸調用processConfigurationClass方法
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
            //省略部分代碼
		}
	}
           

主要對@Import注解标注的類分3種情況進行處理(ImportSelector、ImportBeanDefinitionRegistrar、普通類)。

ImportSelector

ImportSelector分兩種情況:

  1. 如果是直接實作的ImportSelector,則擷取到自定義的ImportSelector,調用selectImports擷取到要導入的指定bean,遞歸調用processImports,出口為processConfigurationClass方法。
  2. 如果是DeferredImportSelector,待所有配置類解析後才會執行導入。
//這個candidate就是解析到的@Import value指定的類
			Class<?> candidateClass = candidate.loadClass();
			//執行個體化實作的ImportSelectorbean
			ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
			this.environment, this.resourceLoader, this.registry);
			//如果實作的是DeferredImportSelector(ImportSelector的子類)
			if (selector instanceof DeferredImportSelector) {
			    //将目前selector bean先緩存下來,這裡不執行selectImports
				this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
			}
			else {
			    //直接實作的ImportSelector,直接調用selectImports,擷取importClassNames
				String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
				Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
				//遞歸調用processImports
				processImports(configClass, currentSourceClass, importSourceClasses, false);
			}
           

ImportBeanDefinitionRegistrar

先緩存起來,先不執行實作了ImportBeanDefinitionRegistrar的方法,在step4完成bean的注冊

Class<?> candidateClass = candidate.loadClass();
		ImportBeanDefinitionRegistrar registrar = ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
										this.environment, this.resourceLoader, this.registry);
		configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
           

普通類

遞歸調用processConfigurationClass方法。

這裡是也對直接實作ImportSelector解析遞歸調用processImports的出口。

this.importStack.registerImport(currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
        //當成配置類進行處理
		processConfigurationClass(candidate.asConfigClass(configClass));
           

解析@ImportResource

用于引入xml形式的bean配置檔案,此步并未真正去解析,隻是先緩存起來,step4完成解析和bean的注冊。

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的methods

此步隻是通過掃描添加了@Bean注解的方法,封裝成BeanMethod緩存起來,真正的bean解析以及注冊在step4。延遲導入。

Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}
	    // Process default methods on interfaces
		processInterfaces(configClass, sourceClass);
           

step4. 完成@Bean、@Import等bean的解析與注冊

經過前一步對配置類的解析,每一個配置類解析後會封裝成ConfigurationClass,這一步針對封裝好的ConfigurationClass繼續完成BeanDefinition的注冊。例如前面解析到的@Bean方法定義的bean、@Import value為ImportBeanDefinitionRegistrar、@ImportedResources指定的bean。

// 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());
			}
			this.reader.loadBeanDefinitions(configClasses);
           

ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

private void loadBeanDefinitionsForConfigurationClass(
			ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
        //省略部分代碼

		if (configClass.isImported()) {
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}
		//處理@Bean的beanDefinitoin注冊
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}
        //處理@ImportedResources的beanDefinitoin注冊
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		//處理@Import下value是ImportBeanDefinitionRegistrar和DeferredImportSelector指定的beanDefinitoin注冊
		loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}
           

@Bean的解析與注冊

根據@Bean指定的方法,解析注解相關值,構造好BeanDefinition相關屬性,最後通過BeanDefinitionRegistry完成bean的注冊。

ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
	    //對應的配置類
		ConfigurationClass configClass = beanMethod.getConfigurationClass();
		//注解資訊
		MethodMetadata metadata = beanMethod.getMetadata();
		//方法名稱
		String methodName = metadata.getMethodName();
       
        //省略部分代碼
        //@Bean注解的屬性值
		AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
		Assert.state(bean != null, "No @Bean annotation attributes");
        //擷取bean名稱,如果注解指定了則取指定的名稱,否則取方法名稱
		// Consider name and any aliases
		List<String> names = new ArrayList<>(Arrays.asList(bean.getStringArray("name")));
		String beanName = (!names.isEmpty() ? names.remove(0) : methodName);
        //注冊别名
		// Register aliases even when overridden
		for (String alias : names) {
			this.registry.registerAlias(beanName, alias);
		}

        //省略部分代碼

        //開始構造BeanDefinition
		ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
		beanDef.setResource(configClass.getResource());
		beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));

		if (metadata.isStatic()) {
		      //省略部分代碼
		}
		else {
		    //設定bean的執行個體化的工廠bean
			// instance @Bean method
			beanDef.setFactoryBeanName(configClass.getBeanName());
			//設定執行個體化的工廠方法
			beanDef.setUniqueFactoryMethodName(methodName);
		}

		if (metadata instanceof StandardMethodMetadata) {
			beanDef.setResolvedFactoryMethod(((StandardMethodMetadata) metadata).getIntrospectedMethod());
		}

		beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
		beanDef.setAttribute(org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor.
				SKIP_REQUIRED_CHECK_ATTRIBUTE, Boolean.TRUE);

		AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata);

		Autowire autowire = bean.getEnum("autowire");
		if (autowire.isAutowire()) {
			beanDef.setAutowireMode(autowire.value());
		}

		boolean autowireCandidate = bean.getBoolean("autowireCandidate");
		if (!autowireCandidate) {
			beanDef.setAutowireCandidate(false);
		}
        //指定bean初始化回調的方法
		String initMethodName = bean.getString("initMethod");
		if (StringUtils.hasText(initMethodName)) {
			beanDef.setInitMethodName(initMethodName);
		}
        //指定bean銷毀時回調的方法
		String destroyMethodName = bean.getString("destroyMethod");
		beanDef.setDestroyMethodName(destroyMethodName);

		// 設定scope
		ScopedProxyMode proxyMode = ScopedProxyMode.NO;
		AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(metadata, Scope.class);
		if (attributes != null) {
			beanDef.setScope(attributes.getString("value"));
			proxyMode = attributes.getEnum("proxyMode");
			if (proxyMode == ScopedProxyMode.DEFAULT) {
				proxyMode = ScopedProxyMode.NO;
			}
		}
		
        //省略部分代碼
		
		//注冊
		this.registry.registerBeanDefinition(beanName, beanDefToRegister);
	}

           

@ImportedResources的解析與注冊

//不分析

@Import注解value是ImportBeanDefinitionRegistrar

邏輯比較簡單,就是從緩存中拿到前面解析到@Import value是ImportBeanDefinitionRegistrar的所有類,循環調用registerBeanDefinitions,完成自定義BeanDefinition的注冊。

private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {
		registrars.forEach((registrar, metadata) ->
				registrar.registerBeanDefinitions(metadata, this.registry, this.importBeanNameGenerator));
	}
           

postProcessBeanFactory

@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);
		//如果postProcessBeanDefinitionRegistry沒有執行,則通過這個判斷來調用processConfigBeanDefinitions重新執行。
		if (!this.registriesPostProcessed.contains(factoryId)) {
			// BeanDefinitionRegistryPostProcessor hook apparently not supported...
			// Simply call processConfigurationClasses lazily at this point then.
			processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
		}
        //利用cglib增強@Configuration的bean
		enhanceConfigurationClasses(beanFactory);
		//添加一個bean後置處理器ImportAwareBeanPostProcessor
		beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
	}
           

CGLIB增強Configuration類

問題:為什麼要增強Configuration類?

帶着這個疑問看下enhanceConfigurationClasses方法。

ConfigurationClassPostProcessor#enhanceConfigurationClasses:

public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
		Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
		for (String beanName : beanFactory.getBeanDefinitionNames()) {
			BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
			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類型的配置類
			if (ConfigurationClassUtils.CONFIGURATION_CLASS_FULL.equals(configClassAttr)) {
                //省略部分代碼
                //存下來,在下面代碼for循環内進行增強處理
				configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
			}
		}
		//沒有full類型的配置類,注解return
		if (configBeanDefs.isEmpty()) {
			// nothing to enhance -> return immediately
			return;
		}
        
        //周遊Configuration類,進行增強
		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();
			//增強
			Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
			if (configClass != enhancedClass) {
				beanDef.setBeanClass(enhancedClass);
			}
		}
	}
           

看enhancer.enhance做了哪些增強:

入口:ConfigurationClassEnhancer#newEnhancer

private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(configSuperClass);
		//繼承了EnhancedConfiguration接口
		enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
		enhancer.setUseFactory(false);
		enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
		enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
		//添加增強的攔截器
		enhancer.setCallbackFilter(CALLBACK_FILTER);
		enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
		return enhancer;
	}
	
	
	private static final ConditionalCallbackFilter CALLBACK_FILTER = new ConditionalCallbackFilter(CALLBACKS);
	
	//兩個攔截器
	// The callbacks to use. Note that these callbacks must be stateless.
	private static final Callback[] CALLBACKS = new Callback[] {
			new BeanMethodInterceptor(),
			new BeanFactoryAwareMethodInterceptor(),
			NoOp.INSTANCE
	};


           

EnhancedConfiguration接口繼承了BeanFactoryAware接口,是以增強能使得Configuration類能拿到BeanFactory,這是增強的第一個作用。

增強添加了兩個攔截器,BeanMethodInterceptor和BeanFactoryAwareMethodInterceptor。

BeanMethodInterceptor:攔截@Bean修飾的方法用于,保證隻能被調用一次,確定傳回的bean是單例的,這是增強第二個作用。

BeanFactoryAwareMethodInterceptor:攔截setBeanFactory方法,set $$beanFactory變量值。

添加ImportAwareBeanPostProcessor

beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
           

ImportAwareBeanPostProcessor的作用是在屬性指派的時候,對是EnhancedConfiguration的bean調用setBeanFactory方法(搭配上面會将Configuration類增強為EnhancedConfiguration類來了解)。

總結

  1. ConfigurationClassPostProcessor利用了BeanDefinitionRegistryPostProcessor能自定義注冊beanDefinition的拓展能力,以及BeanFactoryPostProcessor能對注冊的beanDefinition做修改的拓展能力,進而達到通過注解形式(脫離xml)實作bean的自動注冊。
  2. 通過在自定義注冊beanDefinition階段,掃描到已經注冊的配置類,取得配置類上相關注解元素(即相關配置),進而完成beanDefinition的添加
  3. 上一步注冊的beanDefinition可能依然是一個配置類,則需要反複執行上一步的掃描解析注冊過程,直到沒有配置類為止。
  4. 配置類的定義包括:有@Configuration注解、Component、ComponentScan、Import、ImportResource、方法上有@Bean注解的類,隻要滿足有某一個注解即為配置類。