@Import註解的作用

在@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定義;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章