上一篇: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導入的類能夠從自定義註解中拿屬性值作特殊邏輯判斷。