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