《Spring技术内幕》学习笔记3——IoC容器载入Bean定义资源文件

 

1.SpringIoC容器将Bean定义的资源文件封装为SpringResource之后,接下来要做的就是通过Spring的资源加载器(resourceLoader)读入Bean定义资源文件的过程。对于IoC容器来说,Bean定义的载入过程就是将Bean定义资源文件读入进内存并解析转换成Spring所管理的Bean的数据结构的过程。相对于SpringIoC容器定位Bean定义资源文件来说,Bean定义资源文件的载入和解析过程更复杂一些,因此按照程序的运行步骤逐条分析其实现原理。

2.FileSystemXmlApplicationContext为例分析其载入和解析Bean定义资源文件的过程:

首先从FileSystemXmlApplicationContext的入口构造函数分析起,其代码如下:

 

 

Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContextrefresh()函数启动整个IoC容器对Bean定义的载入过程。

3.AbstractApplicationContextrefresh函数载入Bean定义过程:

 

 

refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中“ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动。

 

AbstractApplicationContextobtainFreshBeanFactory()方法调用子类容器的refreshBeanFactory()方法,启动容器载入Bean定义资源文件的过程,代码如下:

 

 

 

4.AbstractApplicationContext子类的refreshBeanFactory()方法:

AbstractApplicationContext类中只抽象定义了refreshBeanFactory()方法,容器真正调用的是其子类AbstractRefreshableApplicationContext实现的refreshBeanFactory()方法,方法的源码如下:

 

 

refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入。

refreshBeanFactory方法类似,载入Bean定义的方法loadBeanDefinitions也使用了委派模式,在AbstractRefreshableApplicationContext类中只定义了抽象方法,具体的实现调用子类容器中的方法实现。

5.AbstractRefreshableApplicationContext子类的loadBeanDefinitions方法:

AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions方法,容器真正调用的是其子类AbstractXmlApplicationContext对该方法的实现,AbstractXmlApplicationContext的主要源码如下:

 

 

Xml Bean读取器(XmlBeanDefinitionReader)调用其父类AbstractBeanDefinitionReaderreader.loadBeanDefinitions方法读取Bean定义资源。

由于我们使用FileSystemXmlApplicationContext作为例子分析,因此getConfigResources的返回值为null,因此程序执行reader.loadBeanDefinitions(configLocations)分支。

6. AbstractBeanDefinitionReader读取Bean定义资源:

AbstractBeanDefinitionReaderloadBeanDefinitions方法源码如下:

 

 

loadBeanDefinitions(Resource...resources)方法和上面分析的3个方法类似,同样也是调用XmlBeanDefinitionReaderloadBeanDefinitions方法。

从对AbstractBeanDefinitionReaderloadBeanDefinitions方法源码分析可以看出该方法做了以下两件事:

首先,调用资源加载器的获取资源方法resourceLoader.getResource(location),获取到要加载的资源。

其次,真正执行加载功能是其子类XmlBeanDefinitionReaderloadBeanDefinitions方法。

7.资源加载器获取要读入的资源:

 

XmlBeanDefinitionReader通过调用其父类DefaultResourceLoadergetResource方法获取要加载的资源,其源码如下:

 

 

FileSystemXmlApplicationContext容器提供了getResourceByPath方法的实现,就是为了处理既不是classpath标识,又不是URL标识的Resource定位这种情况。

现在,Bean定义的Resource得到了,下面我们继续跟随程序执行方向,分析XmlBeanDefinitionReaderloadBeanDefinitions方法。

8. XmlBeanDefinitionReader加载Bean定义资源:

 

 

 通过源码分析,载入Bean定义资源文件的最后一步是将Bean定义资源转换为Document对象,该过程由documentLoader实现。

9. DocumentLoaderBean定义资源转换为Document对象:

DocumentLoaderBean定义资源转换成Document对象的源码如下:

 

该解析过程调用JavaEE标准的JAXP标准进行处理。

至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。

10.看源代码的个人心得总结:

通过这几天看源码,个人总结一些心得:代码毕竟不是文章,不能从头到尾详细看,个人觉得看源码比较好的方法是:

首先,先实现一个简单例子调用源码,让整个应用能简单跑起来。

然后,在进入代码最开始的地方打一个调试断点,使用Debug工具进行单步调试,直到跑完所有流程。

通过调试就可以理解整个代码的工作流程和调用顺序,有助于理清思路,理解其大概的设计思想。

Spring代码的确实比较复杂,代码中大量使用了设计模式,另外为了解耦合,代码的分工比较明确,对象也非常的多,对于没有分析源码经验的人来说,阅读代码发现其跨度和跳转非常大,难度和挑战比较大。

我也是第一次分析Spring源码,希望和大家一起学习探讨。

 

 

 

 

 

 


 

 

 

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值