美文网首页
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