IoC初始化过程包括:BeanDdefinition的Resource定位、载入和注册三个基本过程。
1、 Resource定位,指BeanDefinition的资源定位。由ResourceLoader通过统一的Resource接口来完成,这个
Resource对各种形式的BeanDefinition的使用提供了统一接口。
2、BeanDefinition载入。把用户定义好的Bean表示成IoC容器内部的数据结构,而这个容器内部的数据结构就是BeanDefinition。
BeanDefinition实际上就是POJO对象在IoC容器中的抽象,通过BeanDefinition定义的数据结构,使IoC容器能够方便管理Bean。
3、BeanDefinition注册。通过BeanDefinitionRegistry接口把载入过程总解析得到的BeanDefinition注册到IoC容器,注入到一个HashMap中。
注意:IoC容器初始化一般不包含Bean依赖注入的实现。Bean定义的载入和依赖注入是两个独立的过程。依赖注入发送在应用第一次通过getBean方法向容器获取Bean时。但是有个特例是:IoC容器预实例化配置的lazyinit属性,如果某个Bean设置了lazyinit属性,则该Bean的依赖注入在IoC容器初始化时就预先完成了。
BeanDefinition的Resource定位
先不去看spring项目启动时候使如何定位的,我们自己创建一个ApplicationContext:
|
|
下面是FileSystemXmlApplicationContext的源码
|
|
AbstractApplicationContext中的refresh()方法,refresh函数是一个模板方法,执行多个方法,而且提供了各(protected)方法的(默认)实现,其子类可以重写它们
|
|
下面重点是AbstractRefreshableApplicationContext类中的refreshBeanFactory()方法:
|
|
载入Definition的信息的方法:
上面我们是手动选择了上下文的类型,以及设置配置文件路径,在spring项目中默认了XmlWebApplicationContext作为上下文,并在web.xml配置文件中设置了配置文件的路径,启动的时候也是按照上面的步骤获取资源。(在spring启动过程 中可以查看配置信息)
通过以上方法可知,到这里我们已经完成了Resource的定位,下面通过返回的Resource对象可以进行BeanDefinition的载入。
BeanDefinition载入
在上面代码我们可以知道,resource定位之后,就开始载入
|
|
resources遍历载入BeanDefinition过程中调用的loadBeanDefinitions(Resource resource)方法在AbstractBeanDefinitionReader没有实现类,由于我们读取的配置文件都是xml文件中的信息,因此载入的实现类时在XmlBeanDefinitionReader中
上面代码可知,BeanDefinition的载入首先通过XML解析器得到Document对象,然后在registerBeanDefinitions(Document doc, Resource resource)方法中安装spring的Bean语义要求进行解析并转化为容器内数据结构,对载入的Bean进行数量统计。
|
|
我们可以发现在BeanDefinitionDocumentReader中,对BeanDenifition的操作是委托给代理BeanDefinitionParserDelegate来操作的,主要是下面的解析方法:
|
|
经过逐层的解析,XML文件中的definition被载入IoC容器中,并创建了数据映射关系,这些数据可以通过AbatractBeanDefinition进行操作。
BeanDefinition的注册
将解析到的BeanDefinition向IoC容器的注册是通过BeanDefinitionReaderUtils中的
registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)方法:
|
|
我们可以发现实现注册功能的最简单的工厂是DefaultListableBeanFactory,
DefaultListableBeanFactory是通过HashMap来持有载入的BeanDefinition的:
在spring4中注册的代码和上面代码是不一样的,不一样的地方是在synchronized加锁的地方不一样
|
|