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)

相关文章
相关标签/搜索