疯狂的小鸡

IOC容器的初始化

字数统计: 701阅读时长: 2 min
2018/10/01 Share

本文章着重分析IOC容器的初始化时的方法链调用。阅读本文章时,强烈建议打开IDE自己跟着方法调用一层层走。建议从AbstractApplicationContext类中的refresh()方法入手。

IoC容器的初始化是由refresh()方法来完成的。这个方法标志着Ioc容器的正式启动。这个方法主要执行三个功能。也就是BeanDefinition的定位、载入和注册。事实上,这个方法实际上应用了模板方法的设计模式,定义了一系列功能,具体的功能实现由子类完成。

定位

定位分两步,第一步是获取Resource。AbstractApplicationContext由于继承了DefaultResourceLoader类而具有了ResourceLoader功能。定位就是ResourceLoader去指定地点读取Resource。还是以ClassPathXmlApplicationContext为例,它就是去指定Path读取.XML文件。读取的数据使用Resource类包装。这里也可以看到使用ApplicationContext的一个好处,由于继承了ResourcePatternResolver接口,ApplicationContext拥有对不同Resource读取的实现。而使用DefaultListableBeanFactory则需根据实际情况为其配置特定的ResourceLoader。 获取到了Resource并不能被DefaultListableBeanFactory直接使用,所以第二步是解析Resource。解析使用的是BeanDefinitionReader的实现类,例如XmlBeanDefinitionReader。解析得到的BeanDefinition将被载入到beanFactory中。

载入

前面提到了refresh中的refreshBeanFactory()方法,这个方法将会销毁现有的BeanFactory并返回一个新的BeanFactory。在这个方法中,有一个loadBeanDefinitions()方法,位于生成新BeanFactory之后,用于启动新BeanFactory对BeanDefinition的载入。

通过对loadBeanDefinitions()方法一层层剥洋葱,我们可以发现loadBeanDefinitions(EncodedResource encodedResource)方法将Resource解析为InputStream,从而知道Resource对象实际上是封装了对目标资源的IO操作。之后调用doLoadBeanDefinitions方法。

在doLoadBeanDefinitions方法中出现了一个新的对象类型Document, 这个对象通过doLoadDocument方法是调用XML解析得到,这里就不做分析了。我们关心的是这个文档树怎么最终被解析并转化成容器内部结构的,这个过程是在registerBeanDefinitions方法中完成的。

通过对registerBeanDefinitions进一步的剥洋葱,最终在BeanDefinitionParserDelegate类中的parseBeanDefinitionElement方法中我们可以看到BeanDefinition的具体解析过程。
解析的结果会被放入BeanDefinitionHolder对象中。BeanDefinitionHolder对象除了持有BeanDefinition外,还持有与该BeanDefinition相关的信息,例如bean的名字,别名集合等。

注册

BeanDefinition经过了定位与载入,在IoC容器中已经有了自己的数据结构和相应的数据表示,但还不能共容器直接使用。需要在容器中注册这些BeanDefinition。注册过程相对简单,在DefaultListableBeanFactory类中持有一个ConcurrentHashMap<String, BeanDefinition>。 并且实现了BeanDefinitionRegistry接口。 调用registerBeanDefinition方法把解析得到的beanDefinition设置到Map里即可。

CATALOG
  1. 1. 定位
  2. 2. 载入
  3. 3. 注册