Spring5 源碼分析-容器刷新-@Import(普通類)

上一篇:Spring5 源碼分析-容器刷新-@ComponentScanjava

功能說明

導入非@Configuration修飾的配置類,@Import導入的配置類能夠有幾種,普通、implements ImportSelector、implements DefferImportSelector,他們最終都可以導入配置,可是生效的時機不同,先說@Import(普通類)spring

舉例Demo

主配置類app

@ComponentScan("com.jv.spring.importannotation.scan")
@Configuration
@Import(ImportConfigClass.class)
public class ImportSpringAppConfig{

}

須要Import的普通配置類,在它上面再使用了一個@ComponentScan註解,指定了另一個掃描路徑,最終將City.class註冊到容器中源碼分析

@ComponentScan("com.jv.spring.importannotation.importscan")
public class ImportConfigClass {
}

查看DEBUG結果post

city對應的Bean已經實例化好,證實導入的普通配置類生效了。this

源碼分析

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

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

		if (checkForCircularImports && isChainedImportOnStack(configClass)) {
			this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
		}
		else {
			this.importStack.push(configClass);
			try {
				//遍歷全部Import進來的配置類候選者
				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 = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						//若是候選者implements DeferredImportSelector接口,先加入待延遲處理列表
						if (selector instanceof DeferredImportSelector) {
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
						else {
							//@Import(ImportSelector實現類)的導入在這裏被遞歸調用直到被直接解析處理
							String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
							Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
							processImports(configClass, currentSourceClass, importSourceClasses, false);
						}
					}
					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());
					}
					else {
						// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
						// process it as an @Configuration class 把普通的配置類當成一個@Configuration修飾的配置類處理
						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();
			}
		}
	}

先判斷是不是ImportSelector,若是是再判斷是不是DeferredImportSelector,若是是則進行處理不然遞歸調用processImportsspa

若是不是ImportSelector,而是ImportBeanDefinitionRegistrar,則將registrar添加到importBeanDefinitionRegistrars.net

若是二者都不是則按照@ConfigurationClass處理--processConfigurationClass()code

 

ImportSelector:blog

配合@Import註解,重寫selectImports方法可完成根據特定的註解或者配置文件的KEY-VALUE讓指定的ImportSelector生效,導入符合要求配置類(配置類能夠不使用@Configuration修飾)

DeferImportSelector:

做用與ImportSelector同樣,可是它是在全部@Configuration配置類都處理完以後纔會被調用。

DeferImportSelector被發現的時候不必定會立馬解析,可能在執行完主parse方法以後纔會被調用,往下還有很深的調用棧,最終會回到processImport()方法,像普通的@Configuration配置類同樣處理

ImportBeanDefinitionRegistrar:

根據從「註冊」階段拿到的ImportBeanDefinitionRegistrar,調用它們的registerBeanDefinitions()方法完成自定義的BeanDefinition掃描和添加邏輯。

Mybatis就是使用的這個東西完成的整合的,具體過程是:在配置類上添加@MapperScan註解,@MapperScan中有Import("MapperScannerRegistrar.class"),而MapperScannerRegistrar中添加了一個MapperScannerConfigurer(它實現了BeanDefinitionRegistryPostProcessor)它的postProcessBeanDefinitionRegistry()方法完成了對Mybatis全部Mapper的掃描與註冊BeanDefinition操做

ImportAware:

ImportAware配合@Import註解做爲元註解使用的時候,被@Import導入的類能夠從自定義註解中拿屬性值作特殊邏輯判斷。

下一篇:Spring5 源碼分析-容器刷新-@Import(類 implments ImportSelector)

相關文章
相關標籤/搜索