详解Spring的ImportSelector接口(2)

写在最前

上篇文章 - 详解Spring的ImportSelector接口(1) //www.greatytc.com/p/aa99a303bc37中,我们最后留下了两个疑问。今天我们先说说第一个疑问 - ImportSelector是如何被Spring框架调用的呢?

ImportSelector是如何被Spring框架调用的呢?

ClassPathXmlApplicationContext

我们以ClassPathXmlApplicationContext为例子,看看Spring在启动过程中是如何调用到ImportSelector接口的。

ClassPathXmlApplicationContext的构造器1

如上图,我们初始化一个ClassPathXmlApplicationContext时需要指定一个xml文件作为应用上下文。该构造器中又调用了另一个构造器,我们跟进去看下:


ClassPathXmlApplicationContext的构造器2

从上面的代码中,我们可以看到在设置完configLocations后调用了refresh()方法。那么,refresh()方法又是干什么的呢?

AbstractApplicationContext的refresh()方法

refresh()定义在ConfigurableApplicationContext接口中,具体的实现在AbstractApplicationContext中,如下:

AbstractApplicationContext.refresh()

从上面的实现中,我们可以看到该方法做了很多准备、初始化、事件通知等工作。具体的我们就不一一看了,今天我们只关心其中的invokeBeanFactoryPostProcessors方法。

AbstractApplicationContext.invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory)

从上面的代码中我们可以看到,invokeBeanFactoryPostProcessors()方法把具体的调用方法委托给了PostProcessorRegistrationDelegate类。另外,从该方法的名字当中我们也可以看出,该方法主要的目的是:实例化,并调用BeanFactoryPostProcessor类的。BeanFactoryPostProcessor是一个接口,有很多的实现类,这里我们就暂且不管BeanFactoryPostProcessor的具体用处了。我们先进入PostProcessorRegistrationDelegate一窥究竟。

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(xxx)方法

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        // 如果有BeanDefinitionRegistryPostProcessors 的话,就先调用它们
        // 处理过的Beans
        Set<String> processedBeans = new HashSet<String>();
        // 是否是BeanDefinitionRegistry类型的BeanFactory. BeanDefinitionRegistry的作用是可以用来注册,删除,获取BeanDefinitions
        if (beanFactory instanceof BeanDefinitionRegistry) {
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
        // 普通类型的BeanFactoryPostProcessor集合
            List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
        // BeanDefinitionRegistry类型的BeanFactoryPostProcessor集合(BeanDefinitionRegistryPostProcessor继承于BeanFactoryPostProcessor)
            List<BeanDefinitionRegistryPostProcessor> registryPostProcessors =
                    new LinkedList<BeanDefinitionRegistryPostProcessor>();
                        
        // 对集合beanFactoryPostProcessors进行分类,如果是BeanDefinitionRegistry类型的BeanFactoryPostProcessor;则调用方法 - postProcessBeanDefinitionRegistry()。、、
        //  postProcessBeanDefinitionRegistry(BeanDefinitionRegistry)该方法的作用是在标准的BeanDefinitions初始化完成后可以修改容器上下文内部的beanDefinition。
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryPostProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryPostProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryPostProcessors.add(registryPostProcessor);
                }
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            // Do not initialize FactoryBeans here: We need to leave all regular beans
            // uninitialized to let the bean factory post-processors apply to them!
            // Separate between BeanDefinitionRegistryPostProcessors that implement
            // PriorityOrdered, Ordered, and the rest.
            // 这里不要初始化FactoryBeans,我们需要保留这些普通的beans 不在这里初始化,目的是为了让bean factory post-processor去处理他们。
           // 根据BeanDefinitionRegistryPostProcessors 实现的不同接口,拆分开来去调用他们。
            String[] postProcessorNames =
                    beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);

            // First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
            // 首先,调用实现了优先级接口 - PriorityOrdered的BeanDefinitionRegistryPostProcessors 
            List<BeanDefinitionRegistryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
            for (String ppName : postProcessorNames) {
                if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                    priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
             // 排序
            sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
            // 添加排序好的优先级PostProcessors到registryPostProcessors集合
            registryPostProcessors.addAll(priorityOrderedPostProcessors);
            // 调用排序好的优先级BeanDefinitionRegistryPostProcessors,postProcessBeanDefinitionRegistry方法会被调用,用来修改,获取,删除容器上下文中的bean定义。
            invokeBeanDefinitionRegistryPostProcessors(priorityOrderedPostProcessors, registry);

            // Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
            // 调用实现了Ordered接口的BeanDefinitionRegistryPostProcessors ,大致逻辑同上PriorityOrdered的处理
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            List<BeanDefinitionRegistryPostProcessor> orderedPostProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
            for (String ppName : postProcessorNames) {
                if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
                    orderedPostProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
                    processedBeans.add(ppName);
                }
            }
            sortPostProcessors(beanFactory, orderedPostProcessors);
            registryPostProcessors.addAll(orderedPostProcessors);
            invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);

            // Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
            // 调用所有其它类型的BeanDefinitionRegistryPostProcessors
            boolean reiterate = true;
            while (reiterate) {
                reiterate = false;
                postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
                for (String ppName : postProcessorNames) {
                    if (!processedBeans.contains(ppName)) {
                        BeanDefinitionRegistryPostProcessor pp = beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class);
                        registryPostProcessors.add(pp);
                        processedBeans.add(ppName);
                        pp.postProcessBeanDefinitionRegistry(registry);
                        reiterate = true;
                    }
                }
            }

            // Now, invoke the postProcessBeanFactory callback of all processors handled so far.
            // 调用所有的BeanDefinitionRegistryPostProcessor的postProcessBeanFactory 方法。
            invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory);
           // 调用容器中BeanFactoryPostProcessor类型的bean(不包含BeanDefinitionRegistryPostProcessor类型的beans)。
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }

        else {
            // Invoke factory processors registered with the context instance.
            // 若beanFactory不是BeanDefinitionRegistry类型的,则直接调用容器中所有的BeanFactoryPostProcessor的postProcessBeanFactory 方法。
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }

          // 下面是BeanFactoryPostProcessor的具体调用过程,和上面的过程很相似,这里就不多说了。
        // Do not initialize FactoryBeans here: We need to leave all regular beans
        // uninitialized to let the bean factory post-processors apply to them!
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
        // Ordered, and the rest.
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        List<String> orderedPostProcessorNames = new ArrayList<String>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
                priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
            }
            else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
                orderedPostProcessorNames.add(ppName);
            }
            else {
                nonOrderedPostProcessorNames.add(ppName);
            }
        }

        // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
        sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // Next, invoke the BeanFactoryPostProcessors that implement Ordered.
        List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        for (String postProcessorName : orderedPostProcessorNames) {
            orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        sortPostProcessors(beanFactory, orderedPostProcessors);
        invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

        // Finally, invoke all other BeanFactoryPostProcessors.
        List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
        for (String postProcessorName : nonOrderedPostProcessorNames) {
            nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
        }
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        beanFactory.clearMetadataCache();
    }

上面的调用关系中,我们可以看出。在这个方法中有两种类型的PostPorcessor被调用处理了;而这两种PostProcessor的关系如下图:


BeanDefinitionRegistryPostProcessor

BeanDefinitionRegistryPostProcessor继承于BeanFactoryPostProcessor。我们大致看看接口定义的方法:

BeanFactoryPostProcessor

postProcessBeanFactory用于在标准的初始化完成后修改容器上下文中的beanFactory。所有bean定义将被加载,但是它们将暂时不被实例化,这允许覆盖,甚至添加一些属性到延迟初始化的bean上。

BeanDefinitionRegistryPostProcessor

postProcessBeanDefinitionRegistry方法在标准化初始化完成后可以修改容器内部的bean definition registry。所有的常规的bean定义都将被加载,但是没有bean被实例化。这允许我们在下一个处理阶段增加一些新的bean定义。

综合上面的逻辑,postProcessBeanDefinitionRegistry是在postProcessBeanFactory方法之前被调用的。

ConfigurationClassPostProcessor

上面说了这么多,目的是为了说明我们的主角 - ConfigurationClassPostProcessor。ConfigurationClassPostProcessor类实现了BeanDefinitionRegistryPostProcessor接口,同时还实现了一些其他的接口,如下图:

ConfigurationClassPostProcessor

ConfigurationClassPostProcessor类实现了父类的postProcessBeanDefinitionRegistry和postProcessBeanFactory方法,如下图:


ConfigurationClassPostProcessor实现父类方法

由上面的分析可知,postProcessBeanDefinitionRegistry方法的调用早于postProcessBeanFactory方法。所有我们先来看看postProcessBeanDefinitionRegistry方法的具体内容:

postProcessBeanDefinitionRegistry

从注释中我们可以看到,这个方法的主要作用是进一步从配置中获取bean的定义,也就是被@Configuration注解修饰的配置类。该方法中又调用了processConfigBeanDefinitions()方法,该方法主要用于处理@Configuration注解。

在processConfigBeanDefinitions方法中又调用了ConfigurationClassParser类的parse方法用于解析@Configuration,如下图:


image.png

我们在进入到ConfigurationClassParser类的parse方法看看,如下:


ConfigurationClassParser.parse()

看到这里,我们终于看见曙光了,终于看见DeferredImportSelector接口了。我们忽略方法中其它部分代码,直接进入到processDeferredImportSelectors()方法一窥究竟。


processDeferredImportSelectors

processDeferredImportSelectors方法中调用了processImports方法执行导入,跟进去看看,在processImports 方法中有很重要的一段代码,如下:

processImports

如上图中代码所示:

  1. 检查类型是否是ImportSelector,如果是则执行第2步。
  2. 如果同时实现了Aware接口和ImportSelector接口,则先调用Aware接口的实现方法;然后进入第三步。
  3. 调用selector的selectImpors方法,把要导入的类的元数据信息作为参数,根据具体的实现逻辑返回要导入的classes。
  4. 执行后续的代码...

说到这里,我们可以看到ImportSelector接口的实现方法selectImports终于被调用成功了。

总结

  1. ImportSelector的导入实现是通过BeanFactoryPostProcessor接口的子接口BeanDefinitionRegistryPostProcessor来实现的。
  2. ImportSelector接口的处理是伴随着@Configuration注解的处理一起处理的。
  3. ImportSelector接口可以实现自定义条件选择性导入classes。
  4. ImportSelector接口的字接口DeferredImportSelector在所有@Configuration处理完成后才被处理的。
  5. 处理ImportSelector接口时,bean定义已经被加载,但是bean还没有被实例化。
  6. Spring Bootn的自动配置功能就是通过DeferredImportSelector接口的实现类EnableAutoConfigurationImportSelector做到的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,814评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,124评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,814评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,924评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,815评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,562评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,944评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,582评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,859评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,881评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,700评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,493评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,943评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,115评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,413评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,978评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,182评论 2 339

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,528评论 18 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 46,684评论 6 342
  • 文章作者:Tyan博客:noahsnail.com 3.4 Dependencies A typical ente...
    SnailTyan阅读 4,122评论 2 7
  • 残雪消融,院中春意渐浓。 早间折下的花枝在修长十指的摆弄下被修剪成长长短短的形状插进白瓷的花瓶中,盛放的,半开的,...
    九重桜阅读 303评论 0 0
  • 今天读《奇特的一生》最后四章 思考:我们对时间的感知? 幼小的孩子对时间的流逝感觉很迟钝;我们对时间的感觉随着年...
    梁木纯阅读 173评论 2 1