天天看點

【八】Spring源碼分析之掃描注冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法一、簡介二、源碼三、checkConfigurationClassCandidate方法四、parser.parse() 五、this.reader.loadBeanDefinitions()

一、簡介

該後置處理器是掃描、解析、注冊所有配置類的Bean

入口

【八】Spring源碼分析之掃描注冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法一、簡介二、源碼三、checkConfigurationClassCandidate方法四、parser.parse() 五、this.reader.loadBeanDefinitions()

 掃描、解析、注冊所有配置類bean的流程圖:

【八】Spring源碼分析之掃描注冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法一、簡介二、源碼三、checkConfigurationClassCandidate方法四、parser.parse() 五、this.reader.loadBeanDefinitions()

二、源碼

ConfigurationClassPostProcessor類processConfigBeanDefinitions方法

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<BeanDefinitionHolder>();
        //  擷取BeanFactory中的beanDefinitionNames,我debug時有8個。
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
					ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}

            // 判斷該bean是否為配置類
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {

                // 我debug的時候最終加到配置類候選的隻有啟動類
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// Return immediately if no @Configuration classes were found
		if (configCandidates.isEmpty()) {
			return;
		}

		// Sort by previously determined @Order value, if applicable

        // 對configCandidates 進行 排序,按照@Order 配置的值進行排序
		Collections.sort(configCandidates, new Comparator<BeanDefinitionHolder>() {
			@Override
			public int compare(BeanDefinitionHolder bd1, BeanDefinitionHolder bd2) {
				int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
				int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
				return (i1 < i2) ? -1 : (i1 > i2) ? 1 : 0;
			}
		});

		// Detect any custom bean name generation strategy supplied through the enclosing application context

        // 檢測是否有自定義bean名稱生成器

		SingletonBeanRegistry singletonRegistry = null;
		if (registry instanceof SingletonBeanRegistry) {
			singletonRegistry = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
				BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
				this.componentScanBeanNameGenerator = generator;
				this.importBeanNameGenerator = generator;
			}
		}

		// Parse each @Configuration class

        // 解析每一個@Configuration注解修飾的配置類

        // 建立配置類解析器
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<BeanDefinitionHolder>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
		do {
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<ConfigurationClass>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}

            // 這個方法主要是把前面解析出來的配置類的beanDefinition都注冊到容器中
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<String>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<String>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition beanDef = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(beanDef.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(beanDef, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		if (singletonRegistry != null) {
			if (!singletonRegistry.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
				singletonRegistry.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
			}
		}

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
			((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
		}
	}
           

做了4件事:

1.擷取BeanFactory中的已注冊的beanDefinitionNames,8個,從中找出@Configuration注解修飾的類,我debug的時候隻有自己寫的啟動類進入了候選配置類。如果找不到@Configuration修飾的配置類,則傳回。對找到的@Configuration修飾的配置類們進行排序。

這裡的candidateNames變量就是Bean工廠中已經有了的beanDefinition的名字,這時有

0 = "org.springframework.context.annotation.internalConfigurationAnnotationProcessor"

1 = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor"

2 = "org.springframework.context.annotation.internalRequiredAnnotationProcessor"

3 = "org.springframework.context.annotation.internalCommonAnnotationProcessor"

4 = "org.springframework.context.event.internalEventListenerProcessor"

5 = "org.springframework.context.event.internalEventListenerFactory"

6 = "app"

7 = "org.springframework.boot.autoconfigure.internalCachingMetadataReaderFactory"

configCandidates變量就是@Configuration注解修飾的類,這裡隻有app

2.檢測是否有自定義bean名稱生成器

3. 解析每一個@Configuration注解修飾的配置類

4.删除緩存

三、checkConfigurationClassCandidate方法

判斷該bean是否為@Configuration修飾的配置類

源碼:

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

        // 擷取類名
		String className = beanDef.getBeanClassName();
		if (className == 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();
			metadata = new StandardAnnotationMetadata(beanClass, true);
		}
		else {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
				metadata = metadataReader.getAnnotationMetadata();
			}
			catch (IOException ex) {
				if (logger.isDebugEnabled()) {
					logger.debug("Could not find class file for introspecting configuration annotations: " + className, ex);
				}
				return false;
			}
		}

        // 如果存在Configuration 注解,則為BeanDefinition 設定configurationClass屬性為full
		if (isFullConfigurationCandidate(metadata)) {
			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
		}


        // 如果AnnotationMetadata 中有Component,ComponentScan,Import,ImportResource 注解中的任意一個,或者存在 被@bean 注解的方法, 則設定configurationClass屬性為lite

		else if (isLiteConfigurationCandidate(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.
		Map<String, Object> orderAttributes = metadata.getAnnotationAttributes(Order.class.getName());
		if (orderAttributes != null) {
			beanDef.setAttribute(ORDER_ATTRIBUTE, orderAttributes.get(AnnotationUtils.VALUE));
		}

		return true;
	}
           

這裡可以看到,判斷是否為配置類的标準是,有@Configuration注解 或者@Component 或者@ComponentScan 或者@Import 或者 @ImportResource 或者@Bean

四、parser.parse()

該方法的入口及往後的調用順序圖:

【八】Spring源碼分析之掃描注冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法一、簡介二、源碼三、checkConfigurationClassCandidate方法四、parser.parse() 五、this.reader.loadBeanDefinitions()

 源碼:ConfigurationClassParser類的parse方法

public void parse(Set<BeanDefinitionHolder> configCandidates) {

        // 執行個體化deferredImportSelectors
		this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

        // 周遊配置類,得到BeanDefinition,根據bd類型不同,調用不用的parse方法解析
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {

                //debug的時候是自己寫的啟動類走的這個if
				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);
			}
		}

        // 處理deferredImportSelectors
		processDeferredImportSelectors();
	}
           

做了3件事

1.執行個體化deferredImportSelectors

2.周遊配置類,得到BeanDefinition,根據bd類型不同,調用不用的parse方法解析

3.處理deferredImportSelectors

這裡的parse方法再往下調用會調到ConfigurationClassParser類的processConfigurationClass方法

4.1ConfigurationClassParser類的processConfigurationClass方法

源碼:

protected void processConfigurationClass(ConfigurationClass configClass) throws IOException {

        // 是否跳過
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

        // 處理Imported
		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);
				for (Iterator<ConfigurationClass> it = this.knownSuperclasses.values().iterator(); it.hasNext(); ) {
					if (configClass.equals(it.next())) {
						it.remove();
					}
				}
			}
		}

		// Recursively process the configuration class and its superclass hierarchy.
		SourceClass sourceClass = asSourceClass(configClass);

        // 遞歸解析
		do {
			sourceClass = doProcessConfigurationClass(configClass, sourceClass);
		}
		while (sourceClass != null);

        // 添加到ConfigurationClassParser的configurationClasses中
		this.configurationClasses.put(configClass, configClass);
	}
           

做了4件事

1.shouldSkip 方法判斷是否跳過:

沒有被@Conditional注解所修飾,傳回false

如果參數中沒有設定條件注解的生效階段,是配置類的話直接使用PARSE_CONFIGURATION階段,遞歸調用shouldSkip,

否則使用REGISTER_BEAN階段,遞歸調用shouldSkip 。擷取配置類的條件注解得到條件資料,并添加到集合中

周遊conditions,進行判斷,如果階段不滿足條件的話,傳回true并跳過這個bean的解析

2.判斷ConfigurationClassParser的configurationClasses中是否已有該配置類,判斷是否需要處理imported

3.遞歸解析

4.添加到ConfigurationClassParser的configurationClasses中

4.1.1ConfigurationClassParser類的doProcessConfigurationClass方法

源碼:

protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException {
		// Recursively process any member (nested) classes first
        // 處理内部類
		processMemberClasses(configClass, sourceClass);

		// Process any @PropertySource annotations
        // 處理@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.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
        // 處理@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) {
				// 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 necessary

                //周遊掃描到的配置類進行解析
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(holder.getBeanDefinition(), this.metadataReaderFactory)) {
						parse(holder.getBeanDefinition().getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
        // 處理@Import注解

		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// Process any @ImportResource annotations.
        // 處理@ImportResource 注解

		if (sourceClass.getMetadata().isAnnotated(ImportResource.class.getName())) {
			AnnotationAttributes importResource =
					AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
			String[] resources = importResource.getStringArray("locations");

            // 周遊配置的locations,加入到configClass 中的ImportedResource
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// Process individual @Bean methods
        // 處理@Bean修飾的方法

		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);

        // 周遊@Bean注釋的方法,添加到configClass
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces

        // 處理接口定義的方法
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any

        // 處理父類
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (!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;
	}
           

 做了8件事:

1.處理内部類

2.處理@PropertySource注解

3.處理@ComponentScan注解

4.處理@Import注解

5.處理@ImportResource注解

6.處理@Bean修飾的方法

7.處理接口定義的方法

8.處理父類

舉個例子,項目目錄:其中App.java有注解@SpringBootApplication,TestConfiguration.java有注解@Configuration,ZipkinController有注解@RestController,TestUser沒有注解。

【八】Spring源碼分析之掃描注冊Bean----ConfigurationClassPostProcessor的processConfigBeanDefinitions方法一、簡介二、源碼三、checkConfigurationClassCandidate方法四、parser.parse() 五、this.reader.loadBeanDefinitions()

到了這個方法後,進來的是app啟動類。

1.app啟動類,它會觸發處理@ComponentScan注解,掃com.sid包下所有bean找到app、ZipkinController、TestUser、TestConfiguration,再從中找出@Component注解修飾的bean,這裡即是(ZipkinController、TestConfiguration),注冊這兩個@Component注解修飾的Bean。此時,把這兩個@Component注解修飾的bean(ZipkinController、TestConfiguration)拿來遞歸調用ConfigurationClassParser類的parser.parse()方法,解析他們。

2.TestConfiguration,ZipkinController進到這個方法後什麼都沒觸發,注冊到容器中。

3.回到上層,繼續是app類在這個方法的後續,它會觸發處理@Import注解,得到兩個處理@Import的類org.springframework.boot.autoconfigure.AutoConfigurationPackages$Registrar

org.springframework.boot.autoconfigure.EnableAutoConfigurationImportSelector

執行個體化他們并且設定到app類Import相關屬性中。

5.結束該方法,結束該方法的上層方法ConfigurationClassParser類的processConfigurationClass方法,回到parser.parse()中繼續往下走,進入processDeferredImportSelectors方法

4.2 processDeferredImportSelectors方法

源碼:

private void processDeferredImportSelectors() {
		List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
		this.deferredImportSelectors = null;
		Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR);

		for (DeferredImportSelectorHolder deferredImport : deferredImports) {
			ConfigurationClass configClass = deferredImport.getConfigurationClass();
			try {

                // getImportSelector得到的是EnableAutoConfigurationImportSelector
                // selectImports調用的是AutoConfigurationImportSelector類的該方法

				String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata());
				processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false);
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
		}
	}
           

 做了2件事:

4.2.1 調用AutoConfigurationImportSelector類的selectImports方法

源碼:

public String[] selectImports(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return NO_IMPORTS;
		}
		try {
			AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
					.loadMetadata(this.beanClassLoader);
			AnnotationAttributes attributes = getAttributes(annotationMetadata);
			List<String> configurations = getCandidateConfigurations(annotationMetadata,
					attributes);
			configurations = removeDuplicates(configurations);
			configurations = sort(configurations, autoConfigurationMetadata);
			Set<String> exclusions = getExclusions(annotationMetadata, attributes);
			checkExcludedClasses(configurations, exclusions);
			configurations.removeAll(exclusions);
			configurations = filter(configurations, autoConfigurationMetadata);
			fireAutoConfigurationImportEvents(configurations, exclusions);
			return configurations.toArray(new String[configurations.size()]);
		}
		catch (IOException ex) {
			throw new IllegalStateException(ex);
		}
	}
           

1 調用AutoConfigurationImportSelector類的selectImports方法,該方法中又調用了getCandidateConfigurations方法。getCandidateConfigurations方法用SpringFactoriesLoader加載了每個引用的包下的spring.factoris檔案中定義的類,從中挑選出factoryName=org.springframework.boot.autoconfigure.EnableAutoConfiguration的類

這裡加載了這3個spring.factoris檔案。其中,隻有spring-boot-autoconfigure-1.5.8.RELEASE.jar!/META-INF/spring.factories檔案中有factoryName=org.springframework.boot.autoconfigure.EnableAutoConfiguration的類96個。

spring-boot-1.5.8.RELEASE.jar!/META-INF/spring.factories

spring-boot-autoconfigure-1.5.8.RELEASE.jar!/META-INF/spring.factories

spring-beans-4.3.7.RELEASE.jar!/META-INF/spring.factories

2. 回到selectImports方法中,把這96個類,排序,去重,移除不要的。

filter方法從spring.factories中得到factoryName=org.springframework.boot.autoconfigure.AutoConfigurationImportFilter的類,即是org.springframework.boot.autoconfigure.condition.OnClassCondition。用Filter過濾掉96個類中不要的,最後隻剩下了 20個類。

3.selectImports方法中fireAutoConfigurationImportEvents方法 ,從spring.factories中得到factoryName=org.springframework.boot.autoconfigure.AutoConfigurationImportListener,即是org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener。使用AutoConfigurationImportEvent事件記錄20個類的評測

4.2.2 調用ConfigurationClassParser類的processImports方法

源碼:

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, boolean checkForCircularImports) throws IOException {

		if (importCandidates.isEmpty()) {
			return;
		}

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				for (SourceClass candidate : importCandidates) {
					if (candidate.isAssignable(ImportSelector.class)) {
						// Candidate class is an ImportSelector -> delegate to it to determine imports
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
						ParserStrategyUtils.invokeAwareMethods(
								selector, this.environment, this.resourceLoader, this.registry);
						if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
							this.deferredImportSelectors.add(
									new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
						}
						else {
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}

                    // 如果@Import導入的類實作了ImportBeanDefinitionRegister接口
					else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
						// Candidate class is an ImportBeanDefinitionRegistrar ->
						// delegate to it to register additional bean definitions
						Class<?> candidateClass = candidate.loadClass();

                        //執行個體化這個@Import導入的類
						ImportBeanDefinitionRegistrar registrar =
								BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);

                        //這個方法裡面一直不滿足執行邏輯的條件,之後補上
						ParserStrategyUtils.invokeAwareMethods(
								registrar, this.environment, this.resourceLoader, this.registry);
                        
						configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class

                        // 這裡基本上是走的這個else
						this.importStack.registerImport(
								currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
						processConfigurationClass(candidate.asConfigClass(configClass));
					}
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" +
						configClass.getMetadata().getClassName() + "]", ex);
			}
			finally {
				this.importStack.pop();
			}
		}
	}
           

1.調用ConfigurationClassParser類的processImports方法,處理這20個類。該方法又會去調用processConfigurationClass方法,裡面調用doProcessConfigurationClass方法,裡面調用doProcessConfigurationClass方法。相當于又把這20個内來拿做了一遍doProcessConfigurationClass方法去處理這20個内中的:内部類、@PropertySource注解、@ComponentScan注解、@Import注解、@ImportResource注解、@Bean修飾的方法、接口定義的方法、父類

 五、this.reader.loadBeanDefinitions()

這裡調用的是ConfigurationClassBeanDefinitionReader類的loadBeanDefinitions方法

源碼:

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {

        // 執行個體化TrackedConditionEvaluator
		TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
		for (ConfigurationClass configClass : configurationModel) {
            // 調用loadBeanDefinitionsForConfigurationClass
			loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
		}
	}
           

loadBeanDefinitionsForConfigurationClass方法源碼:

這個方法主要是把前面解析出來的配置類的beanDefinition都注冊到容器中

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
			TrackedConditionEvaluator trackedConditionEvaluator) {

        // 使用條件注解判斷是否需要跳過這個配置類
		if (trackedConditionEvaluator.shouldSkip(configClass)) {
			String beanName = configClass.getBeanName();

			if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                // 跳過配置類的話在Spring容器中移除bean的注冊
				this.registry.removeBeanDefinition(beanName);
			}
			
            // 從importRegistry 中移除
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
			return;
		}

		if (configClass.isImported()) {
            // 如果自身是被@Import注釋修飾,注冊自己
			registerBeanDefinitionForImportedConfigurationClass(configClass);
		}

        // 将@Bean方法注冊為bean
		for (BeanMethod beanMethod : configClass.getBeanMethods()) {
			loadBeanDefinitionsForBeanMethod(beanMethod);
		}

        // 将configClass中ImportResource指定的資源注冊為bean
		loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
		
        // 如果該類有@Import,且Import進來的類實作了ImportBeanDefinitionRegistrar接口,則調用Import進來的類的registerBeanDefinitions方法。
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
	}
           

做了5件事:

1.使用條件注解判斷是否要跳過配置類,如果要跳過配置類的話,在spring中移除該bean的注冊,從importRegistry 中移除,傳回。

2.如果該bean自身被@Import注釋修飾,注冊自己。

3.将@Bean方法注冊為bean

4.将configClass中中ImportResource指定的資源注冊為bean

5.loadBeanDefinitionsFromRegistrars方法,如果該類有@Import,且Import進來的類實作了ImportBeanDefinitionRegistrar接口,則調用Import進來的類的registerBeanDefinitions方法。

AOP相關的AspectJAutoProxyRegistrar類的registerBeanDefinitions方法(注冊AnnotationAwareAspectJAutoProxyCreator,設定AOP屬性)的調用就是在這裡

繼續閱讀