火眼金睛,看透Spring处理Import注解的全过程

文章目录

一、前言

本文结构:

  1. Enable前缀的注解上面有@Import注解;
  2. 常见的四种Import注解用法列举;
  3. 分析spring源码,揭示Import注解的工作原理;
  4. 官方API文档中的疑问解答;

金手指1:Enable前缀的注解上面有@Import注解;
金手指2:从源码层面查看Spring容器处理Import注解的过程是本文的重点;
金手指3:扫描配置类,扫描@Configuration注解就是在ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法中实现的。

二、Enable前缀的注解上面有@Import注解

金手指:Enable前缀的注解上面有@Import注解
Enable注解表示 使Xxx生效

有很多注解都以Enable为前缀,例如配置异步调用的注解EnableAsync,而这些Enable注解上都有@Import注解,以@EnableAsync注解为例:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
    Class<? extends Annotation> annotation() default Annotation.class;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default Ordered.LOWEST_PRECEDENCE;
}

金手指:EnableAsync注解是使异步生效,其中,使异步调用生效的关键是@Import(AsyncConfigurationSelector.class),通过此注解spring容器会创建AsyncConfigurationSelector实例并调用其selectImports方法,完成异步调用相关的配置;

再多看几个Enable前缀的注解的源码,例如EnableBatchProcessing、EnableCaching、EnableDiscoveryClient等,也都是通过Import来生效的,这种方式值得我们学习,在业务开发中也能用类似方式来对bean实例做控制;

三、常见的四种Import注解用法(根据类Abc的不同类型)

在@Import注解的参数中可以填写类名,例如@Import(Abc.class),根据类Abc的不同类型,spring容器有以下四种处理方式:

  1. 如果 Abc类实现了ImportSelector接口,那么 spring容器就会实例化Abc类,并且调用其selectImports方法;

  2. 如果 Abc类实现了DeferredImportSelector接口(DeferredImportSelector是ImportSelector的子类),那么,spring容器就会实例化Abc类,并且调用其selectImports方法,和ImportSelector的实例不同的是,DeferredImportSelector的实例的selectImports方法调用时机晚于ImportSelector的实例,要等到@Configuration注解中相关的业务全部都处理完了才会调用

(具体逻辑在ConfigurationClassParser.processDeferredImportSelectors方法中),想了解更多DeferredImportSelector和ImportSelector的区别,请参考《ImportSelector与DeferredImportSelector的区别(spring4) 》;

  1. 如果 Abc类实现了ImportBeanDefinitionRegistrar接口,那么 spring容器就会实例化Abc类,并且调用其registerBeanDefinitions方法;

  2. 如果 Abc没有实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一个,那么 spring容器就会实例化Abc类,官方说明在这里;

四、Spring处理@Import注解的过程(全文重点,对应四种@Import注解的解释的源码解析)

金手指:从源码层面查看Spring容器处理Import注解的过程是本文的重点
重要金手指:实际框架中,@Import注解用在修饰Enable前缀的注解,比如springboot的EnableAutoConfiguration注解,eureka的@EnableDiscoveryClient注解或者@EnableEurekaClient注解,当然,这个本文不涉及,本文这里仅涉及Spring如何处理@Import注解

接下来通过spring源码来了解spring容器是如何处理Import注解的;

4.1 refresh()第5个方法invokeBeanFactoryPostProcessors()

先看spring容器的初始化代码,定位AbstractApplicationContext类的refresh方法,里面会调用invokeBeanFactoryPostProcessors方法,如下图红框所示:

在这里插入图片描述

4.2 invokeBeanFactoryPostProcessors()调用PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()

展开invokeBeanFactoryPostProcessors方法,继续追踪到了PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors方法,具体操作如下图红框所示:

在这里插入图片描述

对于上图分析的调用invokeBeanDefinitionRegistryPostProcessors方法时作为入参传入的bean,ConfigurationClassPostProcessor类的实例是符合过滤要求的:既实现了BeanDefinitionRegistryPostProcessor接口,又实现了PriorityOrdered接口。

因此,在invokeBeanDefinitionRegistryPostProcessors方法中,调用ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法。

金手指:调用postProcessBeanDefinitionRegistry()方法很好理解,但是为什么调用转到ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry()方法
理由:ConfigurationClassPostProcessor类的实例是符合过滤要求的:既实现了BeanDefinitionRegistryPostProcessor接口,又实现了PriorityOrdered接口。

4.3 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()调用ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry()

之前在【源码解析008】和【源码解析009】,在 改变bean的定义(BeanFactoryPostProcessor接口) 和 注册bean到spring容器(BeanDefinitionRegistryPostProcessor接口) 在invokeBeanDefinitionRegistryPostProcessors()就直接过了,没有实际进来,现在我们实际进来。

ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry方法中,如下图红框所示,processConfigBeanDefinitions方法负责处理@Configuration注解相关的业务:

在这里插入图片描述

在这里插入图片描述

4.4 ConfigurationClassPostProcessor类的postProcessBeanDefinitionRegistry()调用processConfigBeanDefinitions()方法,这个processConfigBeanDefinitions()方法作用:扫描@Configuration注解

processConfigBeanDefinitions方法代码如下,请注意中文注释:

金手指:扫描配置类,扫描@Configuration注解就是在ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法中实现的,就是ConfigurationClassUtils.checkConfigurationClassCandidate()代码

//被确认为配置类的bean定义都放在集合configCandidates中
Set<BeanDefinitionHolder> configCandidates = new LinkedHashSet<BeanDefinitionHolder>();
//取所有bean的名称
String[] candidateNames = registry.getBeanDefinitionNames();
//逐个检查每个bean
for (String beanName : candidateNames) {
    //取得每个bean的定义对象
    BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
            ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
    }
    //注意:ConfigurationClassUtils.checkConfigurationClassCandidate方法非常值得一看,里面的通过当前类的注解来判断是否为配置类
    else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
        //例如有@Configuration注解的类,被判定为配置类,放入集合configCandidates中
        configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    }
}
// 循环完成了
// 如果一个配置类都没找到,就直接返回了
if (configCandidates.isEmpty()) {
    return;
}

// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry singletonRegistry = null;    // 新建一个局部变量singletonRegistry 
if (registry instanceof SingletonBeanRegistry) {
    singletonRegistry = (SingletonBeanRegistry) registry;   // instanceof判断后强制类型转换
    if (!this.localBeanNameGeneratorSet && singletonRegistry.containsSingleton(CONFIGURATION_BEAN_NAME_GENERATOR)) {
        BeanNameGenerator generator = (BeanNameGenerator) singletonRegistry.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
        this.componentScanBeanNameGenerator = generator;   // 使用得到的局部变量generator赋值两个类变量
        this.importBeanNameGenerator = generator;    // 使用得到的局部变量generator赋值两个类变量
    } 
}

// 实例化ConfigurationClassParser对象,用来处理配置类
ConfigurationClassParser parser = new ConfigurationClassParser(
        this.metadataReaderFactory, this.problemReporter, this.environment,
        this.resourceLoader, this.componentScanBeanNameGenerator, registry);

Set<ConfigurationClass> alreadyParsed = new HashSet<ConfigurationClass>(configCandidates.size());
do {
    // parse方法是处理配置类逻辑的核心代码
    parser.parse(configCandidates);
    parser.validate();

在这里插入图片描述
在这里插入图片描述

金手指:我还看不懂这个,具体怎么识别@Configuration注解的
重要金手指:识别@Configuration注解和处理@Configuration注解都是在ConfigurationClassPostProcessor类的processConfigBeanDefinitions()方法中,都是在一个方法中

4.5 ConfigurationClassParser类的parse()方法

看ConfigurationClassParser类的parse方法:

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        //稍后执行的parse方法中,所有DeferredImportSelector实现类都会被放入集合deferredImportSelectors中
        this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>();

        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 (Exception ex) {
                throw new BeanDefinitionStoreException(
                        "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
            }
        }
        //此方法内,会将集合deferredImportSelectors中的所有对象取出来执行其selectImports方法
        processDeferredImportSelectors();
    }

从上述代码中可以看出,DeferredImportSelector实现类的selectImports方法会在最后被调用,其余的关键逻辑应该在parse(AnnotationMetadata metadata, String beanName)这个关键方法中,顺着这个方法一直追踪下去,直到doProcessConfigurationClass方法,如下图红框所示,所有Import注解的处理,都在processImports方法中

在这里插入图片描述

4.6 processImports()中处理四种情况Import注解

processImports方法中包含了对ImportSelector实现类和ImportBeanDefinitionRegistrar实现类的处理,以及未实现这些接口的类的处理,我们逐个来分析吧,

4.6.1 实现ImportBeanDefinitionRegistrar接口的bean

首先看ImportBeanDefinitionRegistrar实现类的处理,如下图红框位置,

(1)调用configClass.addImportBeanDefinitionRegistrar方法将ImportBeanDefinitionRegistrar实现类存入configClass的成员变量importBeanDefinitionRegistrars中;
(2)后面的ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法中,this.reader.loadBeanDefinitions(configClasses);会调用这些ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法(懂了 good);

小结1:实现ImportBeanDefinitionRegistrar接口的bean,放到类变量configurationClasses里面去了。

金手指:后面的ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法中,this.reader.loadBeanDefinitions(configClasses);会调用这些ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法

在这里插入图片描述

4.6.2 实现ImportSelector接口的bean

再来看processImports方法中对ImportSelector实现类的处理,这里略有些复杂,因为涉及到对processImports方法的迭代调用,请看下图红框旁边的红字说明:

在这里插入图片描述

如上图所示,第二步就是在processImports方法中调用了processImports方法,再次进入processImports之后,会着ImportSelector实现类返回的bean名称直接走到第三步的位置,第三步处理的就是没有实现ImportSelector和ImportBeanDefinitionRegistrar这些接口的普通bean了;

金手指:asSourceClasses()方法的作用,将ImportSelector实现类变为普通类,所有就到第三步的else那里去了
在这里插入图片描述

小结2:实现ImportSelector接口的bean,变成普通类,放到类变量configurationClasses里面去了。

4.6.3 普通类(没有实现ImportSelector和ImportBeanDefinitionRegistrar接口的普通bean)

processImports方法对没有实现ImportSelector和ImportBeanDefinitionRegistrar这些接口的普通bean的处理是执行processConfigurationClass方法,将这些bean放入了成员变量configurationClasses中,如下图红框所示:

小结3:没有实现ImportSelector和ImportBeanDefinitionRegistrar接口的普通bean,放到类变量configurationClasses里面去了。

在这里插入图片描述

结合4.6.1 4.6.2 4.6.3 三个小结
Import注解导入的bean都被保存在类变量confiurationClasses里面去了

4.7 this.reader.loadBeanDefinitions(configClasses);处理满载的类变量configClasses

processImports方法(金手指:处理四种类型的Import)分析完毕,Import注解导入的bean都被保存在ConfigurationClassParser实例中,我们回到ConfigurationClassPostProcessor类的processConfigBeanDefinitions方法,这里,this.reader.loadBeanDefinitions(configClasses);负责处理processImports方法找出的那些打算通过@Import注解来注册到spring容器的bean:

回忆:4.6.1 processImports()中处理四种情况Import注解
第一种,实现ImportBeanDefinitionRegistrar接口的bean
调用configClass.addImportBeanDefinitionRegistrar方法将ImportBeanDefinitionRegistrar实现类存入configClass的成员变量importBeanDefinitionRegistrars中;

在这里插入图片描述

金手指:
processConfigBeanDefinitions()方法中,parser.parse(candidates);完成了,现在看this.reader.loadBeanDefinitions(configClasses);
在这里插入图片描述

展开this.reader.loadBeanDefinitions(configClasses)方法,在ConfigurationClassBeanDefinitionReader类中,是对每个配置类逐个执行loadBeanDefinitionsForConfigurationClass方法:

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
        for (ConfigurationClass configClass : configurationModel) {
            loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }
    }


展开方法,真相大白,
(1)实现了4.6.1 ImportBeanDefinitionRegistrar接口的实例,会执行其registerBeanDefinitions方法,
(2)其余普通的类(分为两种4.6.2和4.6.3),通过loadBeanDefinitionsFromImportedResources方法将其bean定义注册在spring环境:

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass,
            TrackedConditionEvaluator trackedConditionEvaluator) {

        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }
            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
            return;
        }

        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }
        //2、普通的类,通过loadBeanDefinitionsFromImportedResources方法将其bean定义注册在spring环境
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
        //1、实现了ImportBeanDefinitionRegistrar接口的实例,会在loadBeanDefinitionsFromRegistrars方法中执行其registerBeanDefinitions方法
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

金手指:方法调用
在这里插入图片描述

4.8 附加:实现DeferredImportSelector接口的bean

前面将普通类、ImportBeanDefinitionRegistrar实现类、ImportSelector实现类的分析已经完成,对于DeferredImportSelector实现类的处理在processDeferredImportSelectors方法中,其实和ImportSelector实现类的处理并无区别,只是处理时机比起ImportSelector实现类略晚,这里就不多说了;

重要金手指:全文总结(源码解析就是第三部分的四种情况)
1. 普通类(即没有实现ImportBeanDefinitionRegistrar、ImportSelector、DeferredImportSelector等接口的类)会通过ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources方法将bean定义注册到spring容器;
2.ImportSelector实现类,其selectImports方法返回的bean的名称,通过ConfigurationClassParser类的asSourceClass方法转成SourceClass对象,然后被当作普通类处理;
3.DeferredImportSelector实现类的处理和ImportSelector实现类的处理并无区别,只是处理时机比起ImportSelector实现类略晚;(关于DeferredImportSelector具体:查看博客“ImportSelector接口与DeferredImportSelector接口的区别”,就是下一篇博客)
4.ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法会被调用,里面可以注册业务所需的bean定义

五、源码解析:如果实现ImportSelector接口的bean,同时实现了XxxAware

在官方API文档中,对ImportSelector接口的描述如下图所示,红框中的一段意思是: ImportSelector接口的实现类,如果同时也实现了EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware这些接口中的一个或几个,那么这些接口对应的方法优先执行,然后才会执行ImportSelector接口的selectImports:

在这里插入图片描述

上图红框中的描述会让我们不禁疑惑:spring是如何做到的呢?一起来看源码吧:

再次打开ConfigurationClassParser类的processImports方法,如下图两个红框所示,对于@Import注解值中的类,只要实现了ImportBeanDefinitionRegistrar、ImportSelector、DeferredImportSelector等接口中的任何一个,都会调用invokeAwareMethods方法(如果实现的是ImportSelector或DeferredImportSelector接口,此时还没有执行selectImports方法):
在这里插入图片描述

展开invokeAwareMethods方法,真相大白,这里面检查是否实现了EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware等接口,如果实现了就调用对应的方法;

private void invokeAwareMethods(Object importStrategyBean) {
    if (importStrategyBean instanceof Aware) {
        if (importStrategyBean instanceof EnvironmentAware) {
            ((EnvironmentAware) importStrategyBean).setEnvironment(this.environment);
        }
        if (importStrategyBean instanceof ResourceLoaderAware) {
            ((ResourceLoaderAware) importStrategyBean).setResourceLoader(this.resourceLoader);
        }
        if (importStrategyBean instanceof BeanClassLoaderAware) {
            ClassLoader classLoader = (this.registry instanceof ConfigurableBeanFactory ?
                    ((ConfigurableBeanFactory) this.registry).getBeanClassLoader() :
                    this.resourceLoader.getClassLoader());
            ((BeanClassLoaderAware) importStrategyBean).setBeanClassLoader(classLoader);
        }
        if (importStrategyBean instanceof BeanFactoryAware && this.registry instanceof BeanFactory) {
            ((BeanFactoryAware) importStrategyBean).setBeanFactory((BeanFactory) this.registry);
        }
    }
}

至此,源码分析工作已经结束

六、详细解释

6.1 自定义模拟

金手指:模拟的时候,Import实现类只要实现接口就可以了,不用声明为bean
在这里插入图片描述

金手指:顺序问题在这里插入图片描述
这个图也说明了一个顺序问题:
(1)ImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理之前,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理(注意,这里只是对@Bean修饰的方法的处理,并不是立即调用@Bean修饰的方法,这个区别很重要!);
(2)DeferredImportSelector实例的selectImports方法的执行时机,是在@Configguration注解中的其他逻辑被处理完毕之后,所谓的其他逻辑,包括对@ImportResource、@Bean这些注解的处理;
在这里插入图片描述
在这里插入图片描述

6.2 详细过程spring处理Import注解的过程(太详细了,面试用不到这样详细)

6.2.1 第一步,启动工作

AbstractApplicationContext类中的refresh()方法中的invokeBeanFactoryPostProcessors()方法

AbstractApplicationContext类中的invokeBeanFactoryPostProcessors()方法中的PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()方法

PostProcessorRegistrationDelegate类中的invokeBeanFactoryPostProcessors()方法中的invokeBeanDefinitionRegistryPostProcessors()方法

PostProcessorRegistrationDelegate类中的invokeBeanDefinitionRegistryPostProcessors()方法的postProcessor.postProcessBeanDefinitionRegistry()方法

ConfigurationClassPostProcessor类中的postProcessBeanDefinitionRegistry()方法中的processConfigBeanDefinitions()方法

6.2.2 第二步,正式工作

找到@Import注解标注类(通过找实例是否实现了ImportSelector与DeferredImportSelector接口),然后执行其selectImports()方法

ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法中的parser.parse(candidates);(candidates就是配置类集合)

ConfigurationClassParser类中的parse(Set configCandidates)方法中的parse()

ConfigurationClassParser类中的parse()中的processConfigurationClass()方法

递归调用
ConfigurationClassParser类中的processConfigurationClass()方法中的doProcessConfigurationClass()方法

ConfigurationClassParser类中的doProcessConfigurationClass()方法中的processImports()方法

ConfigurationClassParser类中的processImports()方法中的processConfigurationClass()方法

最后,ConfigurationClassParser类中的processConfigurationClass()方法跳出,执行this.configurationClasses.put(configClass, configClass);完成

6.2.3 第三步,实例化工作

ConfigurationClassPostProcessor类中的processConfigBeanDefinitions()方法中的this.reader.loadBeanDefinitions(configClasses);

ConfigurationClassBeanDefinitionReader类中的loadBeanDefinitions()方法中循环调用loadBeanDefinitionsForConfigurationClass()方法;

ConfigurationClassBeanDefinitionReader类中的loadBeanDefinitionsForConfigurationClass方法中调用loadBeanDefinitionsFromImportedResources()方法和loadBeanDefinitionsFromRegistrars()方法;

6.2.4 附:parse()中存在一个递归

在这里插入图片描述

金手指:源码设计优美,一个类中尽量封装这个类的方法,不得已才调用其他类的方法,在设计的时候要设计优美

七、面试金手指

7.1 起手式:Enable前缀的注解上面有@Import注解

金手指:Enable前缀的注解上面有@Import注解
Enable注解表示 使Xxx生效

金手指:EnableAsync注解是使异步生效,其中,使异步调用生效的关键是@Import(AsyncConfigurationSelector.class),通过此注解spring容器会创建AsyncConfigurationSelector实例并调用其selectImports方法,完成异步调用相关的配置;

7.2 重点:常见的四种Import注解用法(根据类Abc的不同类型)

在@Import注解的参数中可以填写类名,例如@Import(Abc.class),根据类Abc的不同类型,spring容器有以下四种处理方式:

  1. 如果 Abc类实现了ImportSelector接口,那么 spring容器就会实例化Abc类,并且调用其selectImports方法;

  2. 如果 Abc类实现了DeferredImportSelector接口(DeferredImportSelector是ImportSelector的子类),那么,spring容器就会实例化Abc类,并且调用其selectImports方法,和ImportSelector的实例不同的是,DeferredImportSelector的实例的selectImports方法调用时机晚于ImportSelector的实例,要等到@Configuration注解中相关的业务全部都处理完了才会调用

(具体逻辑在ConfigurationClassParser.processDeferredImportSelectors方法中),想了解更多DeferredImportSelector和ImportSelector的区别,请参考《ImportSelector与DeferredImportSelector的区别(spring4) 》;

  1. 如果 Abc类实现了ImportBeanDefinitionRegistrar接口,那么 spring容器就会实例化Abc类,并且调用其registerBeanDefinitions方法;

  2. 如果 Abc没有实现ImportSelector、DeferredImportSelector、ImportBeanDefinitionRegistrar等其中的任何一个,那么 spring容器就会实例化Abc类,官方说明在这里;

7.3 重点:Spring处理@Import注解的过程(全文重点,对应四种@Import注解的解释的源码解析)

重要金手指:全文总结(源码解析就是第三部分的四种情况)
1. 普通类(即没有实现ImportBeanDefinitionRegistrar、ImportSelector、DeferredImportSelector等接口的类)会通过ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources方法将bean定义注册到spring容器;
2.ImportSelector实现类,其selectImports方法返回的bean的名称,通过ConfigurationClassParser类的asSourceClass方法转成SourceClass对象,然后被当作普通类处理;
3.DeferredImportSelector实现类的处理和ImportSelector实现类的处理并无区别,只是处理时机比起ImportSelector实现类略晚;(关于DeferredImportSelector具体:查看博客“ImportSelector接口与DeferredImportSelector接口的区别”,就是下一篇博客)
4.ImportBeanDefinitionRegistrar实现类的registerBeanDefinitions方法会被调用,里面可以注册业务所需的bean定义

7.4 附加点:如果实现ImportSelector接口的bean,同时实现了XxxAware

ImportSelector接口的实现类,如果同时也实现了EnvironmentAware、BeanFactoryAware、BeanClassLoaderAware、ResourceLoaderAware这些接口中的一个或几个,那么这些接口对应的方法优先执行,然后才会执行ImportSelector接口的selectImports。

八、小结

Import注解完成,天天打码,天天进步!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祖母绿宝石

打赏一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值