2.3 IoC容器的初始化过程

简单来讲,IoC容器的初始化是由前面介绍的refresh()方法来启动的,这个启动包括BeanDefinition的Resource定位、载入和注册。web

(1) Resource定位过程:数据结构

指的是BeanDefinition的资源定位,由ResourceLoader经过统一的Resource接口来完成,这个Resource对各类形式的BeanDefinition的使用都提供了统一接口。好比文件系统中的Bean定义信息可使用FileSystemResource进行抽象;类路径中的Bean定义信息可使用ClassPathResource来使用等(通常常用该方式,须要把Spring配置文件放在当前项目的classpath路径下。classpath路径指的是当前项目的src目录)。这个定位过程就相似容器寻找数据的过程,就好像水桶装水要先找水。函数

(2) BeanDefinition的载入:spa

把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。3d

(3) 向IoC容器注册这些BeanDefinition的过程:xml

调用BeanDefinitionRegistry接口的实现来完成,把载入过程当中解析获得的BeanDefinition向IoC容器进行注册,在IoC容器内部将BeanDefinition注入到一个HashMap中,IoC容器经过这个HashMap来持有这些BeanDefinition数据。对象

PS:IoC容器初始化过程不包含Bean依赖注入的实现。在Spring中,Bean定义的载入和依赖注入是两个独立过程,依赖注入通常发生在应用第一次经过getBean向容器索取Bean的时候。(例外:若是对某个Bean设置了lazyinit属性,那么这个Bean的依赖注入在IoC容器初始化时就预先完成了)。blog

2.3.1  BeanDefinition的Resource定位

当你使用更为底层的DefaultListableBeanFactory时,首先要定义一个Resource来定位容器使用的BeanDefinition,这个Resource并不能由DefaultListableBeanFactory直接使用,Spring经过BeanDefinitionReader来对这些信息进行处理。相比之下,在更上层的ApplicationContext中,Spring提供了一系列加载不一样Resource的读取器的实现,如FileSystemXmlApplicationContext就提供了从文件系统载入Resource的实现、ClassPathXmlApplication提供了从Class Path载入Resource的实现,XmlWebApplicationContext提供了从web容器中载入Resource的实现。而DefaultListableBeanFactory只是一个纯粹的IoC容器,须要为它配置特定的读取器。索引

在FileSystemXmlApplicationContext中,构造函数实现了对configuration进行处理的功能,让全部配置在文件系统中的以XML文件方式存在的BeanDefinition都可以获得有效处理。构造函数中经过refresh()方法来启动IoC容器的初始化。接口

在初始化FileSystemXmlApplicationContext的过程当中,经过IoC容器的初始化的refresh来启动整个调用,使用的IoC容器是DefaultListableBeanFactory,具体的资源载入在XmlBeanDefinitionReader读入BeanDefinition时完成。而getResourceByPath会被子类FileSystemXmlApplicationContext实现,这个方法返回的是一个FileSystemSource对象,经过这个对象,Spring能够进行相关的I/O操做,完成BeanDefinition的定位。

若是是其余的ApplicationContext,则会产生其余种类的Resource,好比ClassPathResource、ServletContextResource等。

完成资源定位以后,具体的数据尚未导入,数据导入将会在载入和解析中完成,就比如用水桶打水,如今已经找到水源了,可是尚未把水装到桶里。

2.3.2  BeanDefinition的载入和解析

这个载入过程至关于把定义的BeanDefinition在IoC容器中转化成一个Spring内部表示的数据结构的过程。IoC容器对Bean的管理和依赖注入这些功能的实现是经过对其持有的BeanDefinition进行各类相关操做完成的。这些BeanDefinition数据在IoC容器中经过一个HashMap来保持和维护。

在初始化FileSystemXmlApplicationContext的过程当中,经过调用refresh来启动整个BeanDefinition的载入过程,这个初始化经过定义的XmlBeanDefinitionReader来完成。实际使用的IoC容器是DefaultListableBeanFactory,具体的Resource载入在XmlBeanDefinitionReader读入BeanDefinition时实现。因为Spring能够对应不一样形式的BeanDefinition,以XML方式定义就使用XmlBeanDefinitionReader,若是是其余BeanDefinition方式,就须要使用其余种类的BeanDefinitionReader来完成数据载入。

载入是在reader.loadBeanDefinition中开始进行的,这个方法是一个接口方法,具体的实如今XmlBeanDefinitionReader中。在读取器中,须要获得表明XML文件的Resource,由于这个Resource对象封装了对XML文件的I/O操做,因此读取器能够在打开I/O流后获得XML的文件对象,有了这个对象,再经过BeanDefinitionParserDelegate对这个XML的文档树进行解析。

解析并转化为容器内部数据结构是在registerBeanDefinition(doc, resource)中完成的。BeanDefinition的载入分红两部分:

1. 首先经过调用XML的解析器获得document对象;

2. 在完成通用的XML解析之后,按照Spring的Bean规则进行解析。

按照Spring的Bean规则进行解析的过程是在documentReader中实现的,处理的结果由BeanDefinitionHolder对象持有,BeanDefinitionHolder除了持有BeanDefinition之外,还持有好比Bean的名字、别名集合等(BeanDefinitionHolder是BeanDefinition对象的封装类,封装了BeanDefinition,Bean的名字和别名)。

BeanDefinitionHolder的生成是经过BeanDefinitionParserDelegate对XML元素进行解析获得的,BeanDefinitionParserDelegate这个类中包含了对各类Spring Bean定义规则的处理,好比对Bean元素怎么处理,即处理XML文件中出现的<bean></bean>这个最多见的元素信息,在这里会把id、name、aliase等属性元素的值读取出来,设置到生成的BeanDefinitionHolder中去。而对各类Bean的属性配置等比较复杂的解析就经过parseBeanDefinitionElement来完成,并把解析结果设置到BeanDefinitionHolder中。在BeanDefinitionParserDelegate类中,一层一层地对BeanDefinition中的定义进行解析,好比从属性元素集合到具体的每个属性元素,再对具体的属性值的处理,把解析结果封装成PropertyValue对象并设置到BeanDefinition对象中去。

总结:通过这样的逐层解析,XML中定义的BeanDefinition就被整个载入到了IoC容器中,并在容器中创建了数据映射。在IoC容器中创建了对应的数据结构,或者说能够当作是POJO对象在IoC容器中的抽象,这些数据结构能够以AbstractBeanDefinition为入口,让IoC容器执行索引、查询和操做。通过以上的载入过程,IoC容器大体完成了管理Bean对象的数据准备工做(初始化),但依赖注入在这个时候尚未发生,如今,在IoC容器BeanDefinition中存在的只是一些静态的配置信息。

上面所说的过程比较复杂,能够结合如下这个流程图,简单串一下主要的方法。从总体范围来看,载入过程的代码是一步步细化的过程,从web.xml读取的多是多个路径,一个路径下面可能有多个文件(Resource),一个文件里面有多个Bean,一个Bean里面有多个Property,一个Property里面只能有一个Ref、Value和List。

2.3.3  BeanDefinition在IoC容器中的注册

通过载入和解析的过程,用户定义的BeanDefinition信息已经在容器内创建了数据结构,可是这些数据还不能被供容器直接使用,须要在IoC容器中对这些BeanDefinition数据进行注册。那么注册是在哪里发起的?以及注册的实现类?

在DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中,其中一个是去完成BeanDefinition的载入,另外一个是完成注册。在DefaultListableBeanFactory中实现了BeanDefinitionRegistry的接口,这个接口的实现完成了注册,把解析好的BeanDefinition设置到hashMap中。

完成了注册以后就完成了IoC容器的初始化过程。

相关文章
相关标签/搜索