spring步步前行(IOC)-Spring beanFactory详解(二)

前言

​ 承接上一篇,上一篇我们分析了spring beanFactory如何初始化自身,以及如何如何加载我们xml中配置的bean,在此处我们简单的总结下:

  • 1.内部替我们创建了一个DefaultListableBeanFactory,设置序列化id,并提供一些可定制化的设
  • 2.通过XmlBeanDefinitionReader找到我们的xml并解析,将我们配置的bean加载注册到我们的facotry容器中

导语

上一篇我们分析了obtainFreshBeanFactory的方法,我们接着看refresh其他操作方法

在这里插入图片描述

首先我们从refresh整体方法上看,refresh都有什么样子的操作:

  • 允许上下文子类在beanfactory初始化之后修改其内部的beanfactory
  • 注册所有BeanPostProcessor
  • 初始化事件处理集
  • 注册拦截bean创建的所有bean处理器
  • 初始化消息源也就是国际化支持的bean
  • 注册将ApplicationListener实现为侦听器的bean
  • 实例化所有设置单例的bean

等这些操作,接下来,我们从这些方法上一一分析,来了解bean是如何初始化的

refresh的postProcessBeanFactory

首先我们能看到第一个方法postProcessBeanFactory,我们看其实现,看到AbstractApplicatonContext中为空实现,均是由其子类实现,对于AbstractApplicationContext相当于留给子类一个hook方法,这个方法我们延迟放在以后的demo文章尾篇介绍该功能

refresh的invokeBeanFactoryPostProcessors

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

        // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
        // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }

从此处我们可以看到大致操作,可分为两部分

  • 即首先通过getBeanFactoryPostProcessor获取所有已注册的beanFactoryPostProcessor
  • 对获取到的beanFactoryPostProcessor实例化并调用所有

由于PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors的方法过长这里就不贴,我们分析一点贴一点

首先我们一进来就进入了一个if条件判断的方法块中,条件是对BeanDefinitionRegistry的类型进行处理,对于BeanDefinitionRegistry类型的解析,从之前的篇章我们知道,我们的beanfactory为DefaultListableBeanFactory,而DefaultListableBeanFactory自身我们可看到它已实现了BeanDefinitionRegistry接口。


在这里插入图片描述

先new了两个容器,一个盛放的是BeanFactoryPostProcessor,另一个盛放的是BeanDefinitionRegistryPostProssessor。

  • 第一步:还是通过遍历所有已注册的BeanFactoryPostProcessor,若为BeanDefinitionRegistryPostProcessor,先调用自身的postProcessBeanDefinitionRegitstry,让后加入到盛放BeanDefinitionRegistryPostProcessor的容器内,若不是BeanDefinitionRegistryPostProcessor,则直接加入到盛放BeanFactoryPostProcessor的容器内

  • 第二步:从我们的beanfactory的getBeansOfType找出所有实现了BeanDefinitionRegistryPostProcessor,通过OrderCcomparator对这些Processor进行排序,然后遍历执行postProcessBeanDefinitionRegistry

  • 第三步:invokeBeanFactoryPostProcessors具体方法如下:


    在这里插入图片描述

即遍历执行每个postProcessor的postProcessBeanFactory方法进行注册

到这里 , 我们看到的均是对BeanDefinitionRegistryPostProcessor的处理,这里也就是对BeanDefinitonRegistryPostProcessor的处理已经全部完毕, 下面是对BeanFactoryPostProcessor的处理

接下来方法是如下:


在这里插入图片描述
  • 第一步:通过beanFactory的getBeanNamesForType方式查找所有的实现BeanFactoryPostProcessor的类
  • 第二步:声明三个容器,一个盛放实现PriorityOrdered接口的容器,一个盛放实现Ordered接口的beanName的容器,还有一个盛放普通postProcessor的beanName的容器
  • 第三步:对查找出来的所有BeanFactoryPostProcessor的类进行遍历,分类存放对应的类。而priorityOrderedPostProcessor内存放的BeanFactoryPostProcesor则通过beanfactory的getBean方式获取到
  • 第四步:借助OrderComparator对priorityOrderedPostProcessors进行排序,并遍历执行postProcessBeanFactory向beanfactory进行注册
  • 第五步:创建一个orderedPostProcessors容器,遍历orderedPostProcessorNames,向创建的orderedPostProcessors存放通过beanfactory的getBean方式获取到PostProcessor

getBean追踪

从上面的getBean处我们了解需要从beanFactory处获取实例bean我们深入看看,最终我们定位到AbstractFactory的doGetBean


在这里插入图片描述
  • 首先先去实例化好的bean中去找,如果找到,直接返回

  • 去当前beanfactory中父类factory找,如果能找到父类的factory,则叫父类去返回(有点像classloader的双亲模型呀)

  • 开始查看当前要实例化的bean是否依赖于其他的bean,如果依赖,则先实例化依赖的bean,如果依赖的bean还依赖于其他的bean,则接着递归创建


    在这里插入图片描述
  • 如果创建的bean是单例(spring默认单例)接着创建


    在这里插入图片描述
  • 我们跟着createBean看起处理到AbstractAutowireCapableBeanFactory


    在这里插入图片描述

    到这里getbean就为我们准备好了目标的bean

到这里对OrderedPostProcessor的处理,就结束了,紧跟着是对普通PostProcessor的处理,由于一致,这里就不一一分析,将处理代码如下展示:


在这里插入图片描述

可能有人好奇OrderComparator的排序是什么样子的,这里我做简单分析:

public int compare(Object o1, Object o2) {
        boolean p1 = o1 instanceof PriorityOrdered;
        boolean p2 = o2 instanceof PriorityOrdered;
        if(p1 && !p2) {
            return -1;
        } else if(p2 && !p1) {
            return 1;
        } else {
            int i1 = this.getOrder(o1);
            int i2 = this.getOrder(o2);
            return i1 < i2?-1:(i1 > i2?1:0);
        }
    }

public static void sort(List<?> list) {
        if(list.size() > 1) {
            Collections.sort(list, INSTANCE);
        }

    }
其实就是借助Collections进行排序,通过比较getOrder实现排序

至此invokeBeanFactoryPostProcessors部分就分析完毕了,此处我们简单做个总结:

整个invokeBeanFactoryPostProcessros围绕着BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor这两个接口,从上面分析可知,BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor均是注册bean用的,但是BeanDefinitionRegistryPostProcessor执行优先于BeanFactoryPostProcessor
操作3种bean对象向beanfactory中注册
1.beanfactory中之前添加的beanFactoryPostProcessor
2.实现了BeanDefinitionRegistryPostProcessor接口的postProcessor
3.实现了BeanFactoryPostProcessor接口的postProcessor
将这三种bean向beanFactory中注册

refresh的registerBeanPostProcessors

registerBeanPostProcessors和invokeBeanFactoryPostProcessros很相像,
首先先看它的具体方法:


在这里插入图片描述
  • 也是通过beanFactory的getBeanNamesForType找到所有实现BeanPostProcessor的所有类

  • 添加ProcessorChecker这个PostProcessor进beanFactory
    在这里插入图片描述

    很容易,我们发现这个PostProcessor并没有什么特殊操作,只是进行logger.info操作,用来记录一些信息

  • 紧跟着声明了四个容器,和invokeBeanFactoryPostProcessros声明的那三个一致,但是多了一个internalPostProcessors,即用来盛放实现了MergedBeanDefinitionPostProcessor接口的容器(即需要重新注册所有内部BeanPostProcessors)

  • 对priorityOrderedPostProcessor进行分类对于实现了MergedBeanDefinitionPostProcessor就向internalPostProcessor添加一份

  • 紧跟着借助OrderComparator排序,然后遍历priorityOrderedPostProcessors进行注册beanPostProcessor


    在这里插入图片描述

    即通过beanfactory的addBeanPostPrcossor想beanfactory进行注册beanPostprocessor

对于orderedPostProcessorNames和nonOrderedPostProcessorNames处理方式和priorityOrderedPostProcessors一致,唯一不同的跟invokeBeanFactoryPostProcessors一样,通过beanFactory的getBean对name进行替换


在这里插入图片描述

对于internalPostProcessors的操作,即重新注册所有内部BeanPostProcessors:

OrderComparator.sort(internalPostProcessors);
this.registerBeanPostProcessors(beanFactory, internalPostProcessors);

1.排序
2.注册beanPostProcessor
3.通过beanFactory的addBeanPostProcessor添加BeanPostProcessor

最后通过beanFactory的addBeanPostProcessor添加了一个ApplicationListenerDetector的BeanPostProcessor


在这里插入图片描述

可以看到其也是实现了MergedBeanDefinitionPostProcessor,其主要功能是用来检测bean是否是ApplicationListener,如果是判断是否是单例,如果不是单例,那么删除singtonNames中对应的key

由此整个方法也就到这结束了

小小的总结下:

registerBeanPostProcessors与invokeBeanFactoryPostProcessors一致,一个是对BeanPostProcessor的处理,一个是对BeanFactoryPostProcessor的处理,对于BeanPostProcessor而言,对内部的beanPostProcessor重新注册一次

至此对于beanPostProcessor和BeanFactoryPostProcessor,我们就分析到这,我们可以看到spring为我们bean创建等提供了很多由我们自由控制的时机,未避免篇幅太长,后续方法我们下篇继续

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

推荐阅读更多精彩内容