上一篇:Spring5 源码分析-容器刷新-@ComponentScanjava
导入非@Configuration修饰的配置类,@Import导入的配置类能够有几种,普通、implements ImportSelector、implements DefferImportSelector,他们最终都可以导入配置,可是生效的时机不同,先说@Import(普通类)spring
主配置类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导入的类能够从自定义注解中拿属性值作特殊逻辑判断。