在@Import注解的參數中可以填寫類名,例如@Import(Abc.class),根據類Abc的不同類型,spring容器有以下四種處理方式:
- 1. 如果Abc類實現了ImportSelector接口,spring容器就會實例化Abc類,並且調用其selectImports方法;
- 2. DeferredImportSelector是ImportSelector的子類,如果Abc類實現了DeferredImportSelector接口,spring容器就會實例化Abc類,並且調用其selectImports方法,和ImportSelector的實例不同的是,DeferredImportSelector的實例的selectImports方法調用時機晚於ImportSelector的實例,要等到@Configuration注解中相關的業務全部都處理完了才會調用(具體邏輯在ConfigurationClassParser.processDeferredImportSelectors方法中),想了解更多DeferredImportSelector和ImportSelector的區別,請參考《ImportSelector與DeferredImportSelector的區別(spring4) 》;
- 3. 如果Abc類實現了ImportBeanDefinitionRegistrar接口,spring容器就會實例化Abc類,並且調用其registerBeanDefinitions方法;
- 4. 如果Abc沒有實現ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一個,spring容器就會實例化Abc類,官方說明在這里;
spring源碼版本:5.0.5.RELEASE
跟蹤spring容器是如何處理Import注解的,容器初始化一般從AbstractApplicationContext類的refresh開始,其它過程跳過,直接通過堆棧到相關的地方;
doProcessConfigurationClass:300, ConfigurationClassParser {org.springframework.context.annotation} processConfigurationClass:245, ConfigurationClassParser {org.springframework.context.annotation} parse:194, ConfigurationClassParser {org.springframework.context.annotation} doProcessConfigurationClass:293, ConfigurationClassParser {org.springframework.context.annotation} processConfigurationClass:245, ConfigurationClassParser {org.springframework.context.annotation} parse:202, ConfigurationClassParser {org.springframework.context.annotation} parse:170, ConfigurationClassParser {org.springframework.context.annotation} processConfigBeanDefinitions:316, ConfigurationClassPostProcessor {org.springframework.context.annotation} postProcessBeanDefinitionRegistry:233, ConfigurationClassPostProcessor {org.springframework.context.annotation} invokeBeanDefinitionRegistryPostProcessors:273, PostProcessorRegistrationDelegate {org.springframework.context.support} invokeBeanFactoryPostProcessors:93, PostProcessorRegistrationDelegate {org.springframework.context.support} invokeBeanFactoryPostProcessors:694, AbstractApplicationContext {org.springframework.context.support} refresh:532, AbstractApplicationContext {org.springframework.context.support}
ConfigurationClassParser是解析@PropertySources,@ComponentScan,@Import,@ImportResource,@Bean注解的地方
在ConfigurationClassParser#parse中
public void parse(Set<BeanDefinitionHolder> configCandidates) { //稍后執行的parse方法中,所有DeferredImportSelector實現類都會被放入集合deferredImportSelectors中 this.deferredImportSelectors = new LinkedList<>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { if (bd instanceof AnnotatedBeanDefinition) { //在這個parse方法中,所有DeferredImportSelector實現類都會被放入集合deferredImportSelectors中,它們的selectImports方法不會被執行,而其他ImportSelector實現類的selectImports都會被執行 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中的所有對象取出來執行其selectImports方法 processDeferredImportSelectors(); }
查看處理@import的地方
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass) throws IOException { ...... // Process any @Import annotations processImports(configClass, sourceClass, getImports(sourceClass), true); ...... }
跟蹤查看getImports就是遞歸取類的@Import注解的,取到后在processImports方法中進行處理:
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 { for (SourceClass candidate : importCandidates) { //如果是ImportSelector接口的實現類,就在此處理 if (candidate.isAssignable(ImportSelector.class)) { // Candidate class is an ImportSelector -> delegate to it to determine imports Class<?> candidateClass = candidate.loadClass(); //實例化這些ImportSelector的實現類 ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class); //如果這實現類還實現了BeanFactoryAware、EnvironmentAware這些接口,就要先執行這些接口中聲明的方法 ParserStrategyUtils.invokeAwareMethods( selector, this.environment, this.resourceLoader, this.registry); //如果這個實現類也實現了DeferredImportSelector接口,就被加入到集合deferredImportSelectors中,在解析完成后在執行 if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) { this.deferredImportSelectors.add( new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector)); } else { //注意,這一行是關鍵代碼!!!執行實現類的selectImports方法 String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata()); Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames); processImports(configClass, currentSourceClass, importSourceClasses, false); } } //處理ImportBeanDefinitionRegistrar的實現類 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 = BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class); ParserStrategyUtils.invokeAwareMethods( registrar, this.environment, this.resourceLoader, this.registry); //configClass.addImportBeanDefinitionRegistrar方法將ImportBeanDefinitionRegistrar實現類存入configClass的成員變量importBeanDefinitionRegistrars中, //后面的ConfigurationClassPostProcessor類的processConfigBeanDefinitions方法中,處理完parser.parse后在執行 //this.reader.loadBeanDefinitions(configClasses);會調用這些ImportBeanDefinitionRegistrar實現類的registerBeanDefinitions方法 configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata()); } //普通類 else { // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar -> // process it as an @Configuration class 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. 普通類(即沒有實現ImportBeanDefinitionRegistrar、ImportSelector、DeferredImportSelector等接口的類)會通過ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources方法將bean定義注冊到spring容器;
- 2. ImportSelector實現類,其selectImports方法返回的bean的名稱,通過ConfigurationClassParser類的asSourceClass方法轉成SourceClass對象,然后被當作普通類處理;
- 3. ImportSelector與DeferredImportSelector的區別,就是selectImports方法執行時機有差別,這個差別期間,spring容器對此Configguration類做了些其他的邏輯:包括對@ImportResource、@Bean這些注解的處理(注意,這里只是對@Bean修飾的方法的處理,並不是立即調用@Bean修飾的方法,這個區別很重要!);
- 4. ImportBeanDefinitionRegistrar實現類的registerBeanDefinitions方法會被調用,里面可以注冊業務所需的bean定義;