Spring核心:IOC容器的实现(五)
根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象:
从前文可知,其实IOC容器的启动和FileSystemContext本身没什么关系,FileSystemContext只是在基本的IOC容器的基础上,增加了与他相关的特性,而IOC容器的启动(refresh方法),是在AbstractApplicationContext(FileSystemXmlApplicationContext的基类)中执行。
refresh方法-------描述了-----ApplicationContext的初始化过程(BeanFactory的更新,MessageSource和PostProcessor的注册......)
refresh的过程:
![](https://img.haomeiwen.com/i6691799/705c56b4013eb1b2.png)
第一步:创建IOC容器,调用了obtainFreshBeanFactory方法,在这个方法中调用了子类AbstractRefreshableApplicationContext的refreshBeanFactory()方法,而这个方法,才是真正的创建BeanFactory。
refreshBeanFactory:
![](https://img.haomeiwen.com/i6691799/842fc3b01e4bb09d.jpg)
if判断:如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。
customizeBeanFactory():对IoC容器进行定制化,如设置启动参数,开启注解的自动装配等
loadBeanDefinitions():调用载入Bean定义的方法,主要这里又使用了一个委派模式,在当前类中只定义了抽象的loadBeanDefinitions方法,际的载入过程其实是在AbstractRefreshableApplicationContext的子类AbstractXmlApplicationContext中实现。
loadBeanDefinitions:
![](https://img.haomeiwen.com/i6691799/abfa560d1255354e.png)
new XmlBeanDefinitionReader(factory):创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器读取Bean定义资源。
setResourceLoader():为Bean读取器设置Spring资源加载器,父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器,所以这里可以使用this关键字。
setEntityResolver():为Bean读取器设置SAX xml解析器
initBeanDefinitionReader():当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制
loadBeanDefinitions():Bean读取器真正实现加载的方法
![](https://img.haomeiwen.com/i6691799/c30d3b48fe413222.png)
首先得到BeanDefinition信息的Resource定位
直接调用XmlBeanDefinitionReader来读取,具体的载入过程是委托给BeanDefinitionReader完成的。(理由:因为这里的BeanDefinition是通过XML文件定义的,所以应该使用XmlBeanDefinitionReader来载入BeanDefinition)
XmlBeanDefinitionReader中的loadBeanDefinitions:
![](https://img.haomeiwen.com/i6691799/f99fbe2dfc0b82c8.png)
调用BeanDefinitionReader类中的loadBeanDefinitions方法。但是,这个方法是一个模板方法(接口方法),具体的实现在XmlBeanDefinitionReader中。
![](https://img.haomeiwen.com/i6691799/3df73d26029755ec.jpg)
![](https://img.haomeiwen.com/i6691799/352530267b76e19d.jpg)
getResourceLoader():获取在IoC容器初始化过程中设置的资源加载器
getResources():将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源,加载多个指定位置的Bean定义资源文件
loadBeanDefinitions():委派调用其子类XmlBeanDefinitionReader的方法,实现加载功能
else方法内(XmlBeanDefinitionReader通过调用其父类DefaultResourceLoader的getResource方法获取要加载的资源):
将指定位置的Bean定义资源文件解析为Spring IoC容器封装的资源,加载单个指定位置的Bean定义资源文件
DefaultResourceLoader的getResource():
![](https://img.haomeiwen.com/i6691799/2376970d94f56d5f.png)
判断如果是带有classpath标识的Resource,就通过相应方法处理
否则:处理带有URL标识的Resource
从这里我们可以知道:FileSystemXmlApplicationContext容器提供了getResourceByPath方法的实现,就是为了处理既不是classpath标识,又不是URL标识的Resource定位这种情况。
当获取完Resources之后,就要调用XmlBeanDefinitionReader的loadBeanDefinitions方法。
XmlBeanDefinitionReader加载Bean定义资源(获取到Resource之后):
![](https://img.haomeiwen.com/i6691799/cebf79be9fadcc76.png)
![](https://img.haomeiwen.com/i6691799/537af580aad4ee42.png)
this.resourcesCurrentlyBeingLoaded.get();获取线程局部变量
encodedResource.getResource().getInputStream():将资源文件转换为IO输入流
doLoadBeanDefinitions:具体读取过程
![](https://img.haomeiwen.com/i6691799/78f866a043ee32f3.png)
doLoadDocument():将XML文件转换为DOM对象,解析过程由documentLoader实现
registerBeanDefinitions():启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
![](https://img.haomeiwen.com/i6691799/05f1ad1f5cf73708.jpg)
![](https://img.haomeiwen.com/i6691799/05422985fdf7e324.png)
createDocumentBuilderFactory():创建DocumentBuilderFactory对象工厂(创建文件解析器工厂)
createDocumentBuilder():从对象工厂中获取DocumentBuilder对象()。
parse():解析包含了encodedResource资源信息的inputSource
创建文件解析器工厂:
![](https://img.haomeiwen.com/i6691799/4c53507573036ac9.png)
DocumentBuilderFactory.newInstance():创建文档解析工厂
factory.setValidating(true);设置解析XML的校验
至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。