美文网首页
spring源码系列 - spring中的@Import是何如工

spring源码系列 - spring中的@Import是何如工

作者: 黑铁大魔王 | 来源:发表于2020-05-08 21:24 被阅读0次

为了搞清楚springboot的零配置,不得不看@Import
先来写一个简单的代码


这是configuration类

在Appconfig类里,@Import MyClass,这只是一个普通类,并且没有@Component注解


MyClass.java
在main方法里执行完上下文加载后,可以看到,MyClass被初始化了
Main
MyClass的构造方法被打印

那么,可以推测:@Import导入的普通类可以被springbean的生命周期管理
-----------------分割线-----------------
接下来,我们看源码


常规操作,ctrl+左键点它
进入AbstractApplicationContext,看下面截图,
3个方法
这里的3个方法,是看springframework源码的基础入口,
  1. register(AppConfig.class)会把AppConfig注册到bdMap中
  2. 会开启12大护法方法,牛逼的不行哦。。。
    在AbstractApplicationContext的12大护法方法里,invokeBeanFactoryPostProcessors(beanFactory)方法处理的是BeanDefinition与BeanDefinitionMap的事项


    从这里进去看看吧

    从这个入口进去看看


    一步一步往下走
    由于后面的
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);

需要2个参数,所以这里先准备一下这2个参数,首先准备第二个参数


参数2的准备

现在准备第一个参数


参数1的准备
参数都准备好了,就可以进入这个方法了
顾名思义,这个方法用来注册BeanDefinition
这里的postProcessor是ConfigurationClassPostProcessor,调用它的postProcessBeanDefinitionRegistry方法来继续处理
继续调用
image.png
image.png

经过一系列不太复杂的流程,得到了configCandidates,这里只有一个自己写的AppConfig
然后,在经过parse.getConfigurationClasses(),得到configClasses


configClasse们
  1. 拿到了configClasses们,不仅仅只有AppConfig,还有@Import的value类MyClass,为何?可能是因为MyClass也会再次@Import吧。
  2. 调用reader的loadBeanDefinitions,来load bd鸟
    那么,reader又是什么呢?被2挡住了,我再来截个图


    reader是ConfigurationClassBeanDefinitionReader

    reader有了,configClasses们也有了,就可以放心的调用了
    this.reader.loadBeanDefinitions(configClasses);
    再跟进来看


    一次截2个方法的图
    【116】行里有2个类MyClass与AppConfig,可以推测一下,那个会被注册到bdMap里。
    好吧,直接看代码第138行,这里有个判断:configClass.isImported(),判断的是,configClass的ImportBy是否为空,如果是空,那么就不是被import进来的,也就不做import处理,那么,这里只有MyClass会进入138行的判断,进而被注册进入bdMap。
    然后,我们来做一个【支线任务】,【142】行,会取出configClass的所有beanMethod们,然后把他们都注册进入bdMap里,也就是说@Bean,@Bean,@Bean是在这里被注册进beanDefinitionMap里的。

    结束【支线任务】继续往下看,【147】【150】行,是对ImportSelector与ImportBeanDefinitionRegister的处理。
    那么总结一下:在ConfigurationClassBeanDefinitionReader类的

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;
        }

        // @Import普通类,这里注册bdMap, 坑:这是把被import的类自己注册到bdMap里
        if (configClass.isImported()) {
            registerBeanDefinitionForImportedConfigurationClass(configClass);
        }
        // @Bean,这里注册bdMap
        for (BeanMethod beanMethod : configClass.getBeanMethods()) {
            loadBeanDefinitionsForBeanMethod(beanMethod);
        }

        // ImportBeanDefinitionRegister
        loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());

        // ImportSelector
        loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    }

方法里,调用

  1. registerBeanDefinitionForImportedConfigurationClass(configClass);
  2. loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
  3. loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
    来处理@Import的3中方式。
    结束。。。

相关文章

网友评论

      本文标题:spring源码系列 - spring中的@Import是何如工

      本文链接:https://www.haomeiwen.com/subject/xgyqnhtx.html