SpringIOC容器初始化解读--初级篇,绝对让你懂

本文从xml配置方式来解读IOC容器,其他方式其实大同小异

xml配置的方式使用spring离不开一个类叫ClassPathXmlApplicationContext

也是我们最开始学习spring的时候见到的一个类,第一眼看到的时候就觉得哇,名字好长

虽然名字长,但是它很简单,只有一个属性Resource[] 数组(不包括父类的属性),甚至方法也只有一个getConfigResources方法

其余全是构造方法

SpringIOC容器初始化解读--初级篇,绝对让你懂_第1张图片

那么很明显,该类最重要的就是构造方法中完成的一些事了

SpringIOC容器初始化解读--初级篇,绝对让你懂_第2张图片

Resource很明显,是资源,简单来说spring通过ResouceLoader加载xml中的配置,将文本资源转化成JAVA对象Resouce

从上述源码中可以看到,new的ClassPathResource就是Resource的实例对象,通过路径和class,这个过程我们不细说,因为对于开发者而言,其实不重要,我们只需要知道它是怎么来的就行了

下面进入正题,该构造方法的最后一行代码,refresh,跟进去

进去一看,发现,看起来挺简单的昂!(那只能说是spring封装的好,spring源码要是简单,我都能找到女朋友了)

相信很多小伙伴都看过各个博客书籍里对refresh的一些讲解,那既然是初级篇。

我不可能把refresh每一行代码都交代清楚,一我没这个能力,二我可能三天三夜也写不完

那我们挑重点来讲(但是逻辑不会挑,肯定是一步步来)

首先我们把refresh里的方法列出来

SpringIOC容器初始化解读--初级篇,绝对让你懂_第3张图片

英文好的同学其实可以看到每一个方法上的注释,就可以知道每个方法大致是干啥的

第一个方法,prepareRefresh()刷新前的预处理,不重要,大致说一下,初始化一些属性设置,子类自定义个性化的属性,设置方法,检验属性的合法等,保存容器中的一些早期的事件,ignore!

第二个方法,obtainFreshBeanFactory(),这个方法就比较重要了,先不管啥意思,看到BeanFactory,如果了解工厂方法就应该想的到,beanFactory就是管理创建bean的一个工厂。那看这个方法名,obtain什么意思?获取。那很明显了。这个方法就是获取返回一个beanFactory的。二话不说跟进去!因为spring源码很绕,我不可能全截图,太乱,我只截关键步骤。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第4张图片

看到了,该方法就2步,第一步,刷新创建工厂,第二部,返回工厂。那第一步就是关键,第二步的方法其实和第一步都是同一个类AbstractRefreshableApplicationContext实现的,返回的也是该类的一个属性

SpringIOC容器初始化解读--初级篇,绝对让你懂_第5张图片

这里,务必先记住这个DefasultListableBeanFactory这个类,很多人说,这个类是IOC容器的始祖,我是挺赞同的,后续很多操作都会围绕这它来进行。给你们30秒时间,背下这个单词。

接下来,回归正题,看refreshBeanFactory这个方法

SpringIOC容器初始化解读--初级篇,绝对让你懂_第6张图片

这个方法里重要的就这一行,createBeanFactory,很明显吧,创建BeanFactory,接下去其实就不用跟了,如果有兴趣的话可以进去看下,就是new了个实例。那我们看到了,这一步将IOC容器的始祖给实例化了。那刚才说的第二步就是返回这个DefaultListableBeanFactory。

目前为止,前两步完了,是不是还挺容易?那么,继续看。

第三个方法,prepareBeanFactory(beanFactory),看方法名字也看得出来,就是对我们刚才得到的IOC容器始祖做一些预处理,

这个方法,我们跟进去大致看一眼,就看一眼昂,看一眼其实就明白大致了。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第7张图片

哎哟喂,各种set、add、register方法,很明显,给这个beanFactory设置添加注册一些东西。这些都是什么东西?没看标题是初级篇吗?别问,问就是不知道。咳咳,其实看名字也能看出点东西,大致就是一些beanClassLoader类加载器啊,BeanPostProcesser后置处理器啊,忽略一些自动装配的接口啊,添加一些组件啊什么的。真的不用细究,之后我会在后续文章中具体聊一下这些东西。

回来,第四步。

postProcessBeanFactory(beanFactory),看名字就是BeanFactory准备工作完成后进行的后置处理工作

跟进去一看

妈的是个空实现,那么很明显是供给子类去实现的。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第8张图片

那我们看一下,红框框起来的都是有具体实现的,感兴趣的同学可以自己进去看看,但是我们可以猜到(其实就是我猜的,不保证一定对昂),这些spring自己实现的子类,就是根据不同的情况,对beanFactory做出不同的后置处理,看名字,有一些比较熟悉的单词,Web,Servlet,Resource.........算了,不说了,我也没仔细看过,好了,我们知道这一步是干啥的就行了。注意!初级篇!这是初级篇!重要的事说三遍,这些实现具体干嘛你问阿里的面试官也不一定知道呀不是。

so,第五步

invokeBeanFactoryPostProcessors(beanFactory);执行BeanFactoryPostProcessor的方法

SpringIOC容器初始化解读--初级篇,绝对让你懂_第9张图片

那在这之前。我们得了解什么是BeanFactoryPostProcessors,其实spring中还有一个BeanPostProcessors,我们可以简单理解为是针对bean级别和bean工厂级别的两个后置处理器,那具体是用来干嘛的呢?我们知道,作为一个优秀的框架,肯定是要满足开闭原则,可扩展性强,如果我们一开始定义的bean信息不能满足扩展,那spring也就没那么diao了(不就是把对象实例化丢到map里去嘛,切,哈哈哈哈,开玩笑)。后置处理器,就是针对在bean被初始化之前,可以对bean信息作一些修改扩展,那他是怎么做的。我们来看一下这个类。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第10张图片

开心,就只有一个方法,不晕吧?我们再看下这个参数ConfigurableListableBeanFactory,并把它的方法都列出来瞅瞅看看是干啥的

SpringIOC容器初始化解读--初级篇,绝对让你懂_第11张图片

我框2个你们肯定能看懂的方法,获取bean的定义信息和获取bean名字的迭代器。那它是个接口。我们看下它有哪些实现。接下来就见证奇迹的时刻!

看到没??只有一个实现(忽略那个被抛弃的方法),什么实现?还记得吗?IOC始祖DefaultListableBeanFactory,刚才让大家记住的,是不是又回到这里了?根据接口提供的方法,结合我们一开始说的bean工厂就是来创建管理bean的工厂,bean的创建就是通过加载的beanDefinition定义信息去创建的。我们把DefaultListableBeanFactory的属性贴出来看看

SpringIOC容器初始化解读--初级篇,绝对让你懂_第12张图片

看到没,各种容器,根据名字大家也能猜到存的都是些什么东西。后置处理器,就是通过该类去获取定义的bean的信息,再去做自己的修改,再存回到这些容器中,供后续创建使用。明白了什么是后置处理器和它的原理了没?是不是也挺简单的。就是从容器中get,在修改一下set回去嘛,也没什么了不起的。

了解了后置处理器,那对于调用那些后置处理器的方法,我们也就知道干什么的了。

 

接下来,第六步

registerBeanPostProcessors(beanFactory);熟悉吗?刚才提过,spring提供了2个可以对bean做扩展的后置处理器,一个是工厂级别,一个是bean级别的,这里要做的就是注册bean级别的后置处理器。

进去瞄一眼,就一眼昂,不细看。这就不截图了,因为方法体比较长,大家可以自行跟进去看,其实很简单,就是找到这些后置处理器,加入到beanFactory中,在beanFactory中有个list集合专门用来存放beanPostProcessor。

这里我们也看到用的是个写时复制容器,这里可以说点题外话,写时复制容器是个并发容器,用空间换时间,写操作在容器的一个副本上进行,读的时候在老容器里找,这种读写分离,大大加快了寻找遍历这些处理器的效率,为什么说spring牛逼,这就很抠细节,不放过每一个可优化的地方,这应用场景,我们知道写一般就在这一步,之后基本不会再往里面写数据,真的spring的源码随便拿出点东西来都值得细细品。别嫌我话多,这种联系起来的记忆,不会容易忘记。好了,了解这一步做了什么之后。再看下一步。

 

其实第七步,第八步,第九步,甚至包括第十步,现在都可以先跳过去,我们稍微提一提这4步先。

initMessageSource();初始化MessageSource组件(做国际化功能;消息绑定,消息解析)

initApplicationEventMulticaster();初始化事件派发器

onRefresh();留给子容器(子类)

registerListeners();给容器中将所有项目里面的ApplicationListener注册进来

我个人觉得昂,这几部,说重要吧,肯定重要,spring中基本没有无用的代码,都很精辟,但是就对于IOC容器的初始化而言,这些其实目前都不需要太了解,只需要知道在初始化的时候做了这些事就行了。

那我们就继续来说,对于我们开发而言最能近距离感受的一步

finishBeanFactoryInitialization(beanFactory),初始化所有剩下的bean

SpringIOC容器初始化解读--初级篇,绝对让你懂_第13张图片

这里。我框了2个段。其他的,不重要。首先我们来看getBean,猜也能猜到,通过beanFactory获取bean的名字,然后去get,那它是怎么get的呢,这里步骤比较多,我们一步一步来(根据我的截图)

SpringIOC容器初始化解读--初级篇,绝对让你懂_第14张图片

SpringIOC容器初始化解读--初级篇,绝对让你懂_第15张图片

经过3连跳,终于找到了主要的一个方法,doGetBean,这个方法很长,我们挑重点。

首先它会直接去缓存中get单例对象,前面也说过,或者你跟进去看一下,就会知道,就是从一个map中获取Object,这里值得一提的是,这个map是DefaultSingletonBeanRegistry类的一个属性,而我们之前说到的IOC容器始祖DefaultListableBeanFactory也继承自这个类,所以我们也可以理解成,就是从DefaultListableBeanFactory中获取Objcet对象。

当然第一次初始化的时候,这些map肯定是空的,需要一个创建的过程。

那么继续。

我们找到创建bean的地方,根据注释,我们找到这段代码

SpringIOC容器初始化解读--初级篇,绝对让你懂_第16张图片

显而易见,创建bean实例,这里用了个lambda表达式昂,其实是实现的一个ObjectFactory的匿名内部类

这里只有一个方法,createBean,是不是离我们的目标越来越近了。稍等一会,我们先看看这个mdb是什么东西。

我们看到又是从一个map中获取bean的定义信息,而这个类叫AbstractBeanFactory,熟悉不,没错,它也是我们的IOC容器始祖DefaultListableBeanFactory的一个爸爸。前面我们说过了。IOC容器的始祖持有很多很多map,其中就有保存bean定义信息的容器,是不是发现哪里都离不开DefaultListableBeanFactory。好了。拿到了这些bean定义信息,和bean的名字。其实就可以开始创建bean实例了。

然后,进createBean方法里面去看!

进去之后发现代码很长,我们只需要跟着注释走,首先看到这个

SpringIOC容器初始化解读--初级篇,绝对让你懂_第17张图片

熟悉吗,即便你不知道这方法是干啥的,根据我们刚才提过的beanPostProcessor这个bean前置处理器,也知道,这里要做个拦截,翻译过来就是 给beanPostProcessor一个机会去返回一个代理对象来替代目标bean实例。这个方法跟进去看,就能看到,就是从beanFactory中拿到一开始我们说到的bean的一些信息,然后做一些处理。顺便提一句,我们自己也可以去实现后置处理器,去对我们自己的bean做拦截,做一些自己的事情。刚才说到注册bean后置处理器的时候,会把我们自定义的后置处理器也会加到那个写实复制容器中去,供在这里使用。是不是串起来了昂?

好,接下去。真相终于要浮出水面了。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第18张图片

再也没有比这种命名方式更直白的了,创建bean。进去

SpringIOC容器初始化解读--初级篇,绝对让你懂_第19张图片

我们可以看到,再也没有什么乱七八糟的,第一行就是开始了bean的初始化,这里有人不禁要问了,BeanWrapper又是什么东西,说明你的英文不过关啊,Wrapper什么意思??包装。那BeanWrapper是什么东西,不就是对bean做了一层包装吗。

我们先不去管这个包装类具体的内容,先进我们的creatreBeanInstance方法看看它的创建实例过程。

bean的名字和相关定义信息都有了,那么

SpringIOC容器初始化解读--初级篇,绝对让你懂_第20张图片

我们看到有很多return,就是根据特殊的情况去调用不同的方法返回不同的BeanWrapper

那我们看哪个呢?看最后一个

注释不能再直白了,翻译:没有特殊处理,简单的使用没有参数的构造器。用JAVA来说,就是new HelloWorld(),调用无参构造new出实例。那我们又可以猜到,spring肯定不会这样new,不然怎么让它装逼呢,对吧,大家应该也都知道,是怎么创建的?

反射,没错,就是反射。进去看。这里要进2层

SpringIOC容器初始化解读--初级篇,绝对让你懂_第21张图片

SpringIOC容器初始化解读--初级篇,绝对让你懂_第22张图片

熟悉反射的同学,应该很熟悉这些代码吧?

获取class的构造器

然后

再进去看

SpringIOC容器初始化解读--初级篇,绝对让你懂_第23张图片

这2个方法熟悉吧?我们学习反射的时候是不是要setAccesible(true),再调用newInstance(),其实就是一模一样的。

好了。到这里为止,我们的bean实例化好了。然后呢,我们回到这里。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第24张图片

通过返回的bean包装类,获取bean。

拿到bean之后干嘛呢,还有一些事情要做,比如要执行bean的init方法之类的。这些我们就不细看了。

总之我们知道bean拿到了,然后返回了什么呢

英文学的好,真的很重要,这单词,我认识昂,我拿我的女朋友发誓,我没有查字典昂,显露出来的Object,千呼万唤屎出来,这就是最终显露出来的我们的对象。

那我们又有疑问了,不是说spring创建的bean会被放入map里面去吗?我们都知道,IOC容器初始化的时候,只会把单实例对象放入map中,否则将会在调用的时候再创建bean,所以,还记得这一步最开始的截图吗

SpringIOC容器初始化解读--初级篇,绝对让你懂_第25张图片

最后一行方法,初始化所有剩余的非懒加载的单实例。这里我就不细说源码了,因为在getBean里其实已经讲过了。你跟进去会发现,哇,原来长的一样,也是调用了getBean,然后doGetBean,还记得这行代码吗。

SpringIOC容器初始化解读--初级篇,绝对让你懂_第26张图片

刚才我们直接看了createBean,但现在我们回过头来看getSingleton这个方法

直接跳到最后

SpringIOC容器初始化解读--初级篇,绝对让你懂_第27张图片

它在前面做了判断,如果是单例,就调用addSingleton方法,很明显吗,就是把beanName作为key,单例对象作为value添加到一个map中去

SpringIOC容器初始化解读--初级篇,绝对让你懂_第28张图片

 

SpringIOC容器初始化解读--初级篇,绝对让你懂_第29张图片

终于找到了,我们平时所定义的单实例bean它原来就存放在这一个ConcurentHashMap里。

你以为结束了吗。哦不。

 

spring的源码,哎,不周全不死,在refresh中,还有最后一步。

finishRefresh();完成BeanFactory的初始化创建工作

这里面也做了一些后置处理器的初始化,回调了上面说过的需要子类去实现的onfresh方法等等。

感兴趣的话大家可以去看看源码。

哎哟,好累。我感觉这整个过程,如果大家跟着一步一步看下来,应该能明白这整一个过程。

我可是整整跟了数十遍,才理出来这篇文章,希望大家能够有所收获。

你可能感兴趣的:(Spring)