spring中,IOC容器的初始化分成三个步骤:资源文件定位、bean的加载和注册。
资源文件定位
我们以FileSystemXmlApplicationContext的资源定位为例,它是在DefaultResourceLoader的getResource方法中实现,如果是以classpath定位,就返回ClassPathResource,如果是以URL定位,就返回UrlResource,否则就从FileSystemXmlApplicationContext中覆写的getResourceByPath方法中获取,返回FileSystemResource。
这是DefaultResourceLoader的getResource方法:
这是FileSystemXmlApplicationContext中覆写的getResourceByPath方法:
bean的加载和注册
在spring中,会将资源文件中的bean解析成BeanDefinition,这其中,主要是经由下面几个步骤完成:
- 创建BeanFactory
- 根据BeanFactory创建BeanDefinitionDocumentReader
- 在BeanDefinitionDocumentReader使用loadBeanDefinitions进行bean的加载
- 将资源文件转换为Document,并创建BeanDefinitionDocumentReader
- 创建BeanDefinitionParserDelegate,并在BeanDefinitionParserDelegate中解析Document,将bean转换成BeanDefinition对象,最后再封装成BeanDefinitionHolder对象
- 使用BeanDefinitionReaderUtils将BeanDefinition对象添加到一个ConcurrentHashMap中,完成注册。
实例解析
接下来,我们以FileSystemXmlApplicationContext为例,进行IOC容器初始化源码解读。
在FileSystemXmlApplicationContext构造器中调用refresh方法启动IOC容器初始化
refresh方法在AbstractApplicationContext中实现
接下来进入obtainFreshBeanFactory方法中创建BeanFactory
进入AbstractRefreshableApplicationContext的refreshBeanFactory方法。如果容器中已存在BeanFactory,就要先摧毁掉。
进入AbstractXmlApplicationContext的loadBeanDefinitions方法,创建XmlBeanDefinitionReader
进入loadBeanDefinitions,开始使用XmlBeanDefinitionReader进行bean的加载和注册
进入AbstractBeanDefinitionReader的loadBeanDefinitions方法
AbstractBeanDefinitionReader的loadBeanDefinitions(String)
AbstractBeanDefinitionReader的loadBeanDefinitions(String, Set)
AbstractBeanDefinitionReader的loadBeanDefinitions(Resource[])
8.接下来进入XmlBeanDefinitionReader的loadBeanDefinitions
9.在XmlBeanDefinitionReader的doLoadBeanDefinitions里,将资源文件转换为Document
10.进入registerBeanDefinitions里,创建BeanDefinitionDocumentReader,并用来进行bean的加载和注册
进入DefaultBeanDefinitionDocumentReader的registerBeanDefinitions
11.进入doRegisterBeanDefinitions,创建BeanDefinitionParserDelegate
进入DefaultBeanDefinitionDocumentReader的parseBeanDefinitions,开始解析Document
12.进入parseDefaultElement中,我们看bean的解析过程
13.进入DefaultBeanDefinitionDocumentReader的processBeanDefinition,这里使用BeanDefinitionParserDelegate解析bean后返回BeanDefinitionHolder,再用BeanDefinitionReaderUtils进行注册
14.我们先进入BeanDefinitionParserDelegate的parseBeanDefinitionElement,看bean的解析过程
进入BeanDefinitionParserDelegate的parseBeanDefinitionElementparseBeanDefinitionElement,在这里会先将bean解析成AbstractBeanDefinition,然后将AbstractBeanDefinition封装到BeanDefinitionHolder后返回
15.接下来进入BeanDefinitionParserDelegate的parseBeanDefinitionElement,这里会具体解析xml文件中,每个bean节点的信息,包括class,property,parent等,里面的具体解析过程,大家自己去看哈。
16.回到13,我们到BeanDefinitionReaderUtils的registerBeanDefinition看bean的注册过程。这里会调用BeanDefinitionRegistry进行注册,然后将BeanDefinitionHolder中的beanName与别名关联起来。
17.我们看SimpleBeanDefinitionRegistry中的registerBeanDefinition,他的注册过程就是将BeanDefinition存储在一个ConcurrentHashMap中。
以上就是一个完整的IOC容器初始化过程。