Spring-IOC学习-02 IOC容器初始化
上次说到spring IOC 过程中的几个重要接口: Resource, BeanDefinition, BeanDefinitionRender ,BeanFactory, ApplicationContext
简单说了spring 的bean初始化流程:由 Resource接口的具体实现定位,读取资源文件。交给BeanfinintionRender进行bean的解析解析得到
bean的描述对象BeanDefinition 。最后 BeanDefinitionRegister 会将已经等到的bean注册到 BeanFactory 容器中去完成bean的实例化
过程。
首先请看一个简单使用Spring的代码:
不知道有没有这样使用过spring呢!这正是上面所说的spring在IOC初始化时的三个步骤。这样的获取是不是让你更明白IOC的初始化脉络?
我们可以将 IOC容器初始化(bean的实例化) 过程分为 3 个部分 A:资源文件的定位 B:bean的解析,加载 C:bean的"注册"将解析后的BeanDefinition对象注册到BeanFactory
中去.(该初始化过程是不包涵Bean 的依赖注入的 ,何时完成依赖呢? ) 慢慢往下看吧......
步骤1: BeanDefinition 资源文件的定位。
上次说到spring 中有个重要的接口Resource 该接口负责Spring 资源文件的加载读取等操作.Reource根据不同的文件类型定位BeanDefinition。
还记得FileSystemResource,ClassPathResource这俩个子类吗?他们都是 Resource 的具体实现。分别读取不同路径下的资源文件获取BeanDefinition
查看上面的代码Spring 通过Resource 来定位BeanDefinition资源文件,然后在使用BeanDefinitionRender来将定位的资源文件处理后得到Spring要使用的BeanDefinition
对象。因为我们使用的是单纯的容器仅仅是一个能装载 bean 的容器而已所以对于要使用什么样的Resource,什么样的BeanDefinitioRender都是由我们自己说了算的,所以这里就
很灵活了但是,因为什么都要自己定制工作量就上来了。
为什么会这么说?还记得ApplicationContext这个NB的接口吗?找个具体实现去看看吧为啥咱们在使用spring提供的这个接口的时候不用这写额外操作呢?因为别人办理做了呀看
看别人怎么做的吧!
怎么样很简单吧!!!!
既然他已经得到了具体的Resource,那么FileSystemApplicationContext是怎样进行数据处理的,他是如何初始化BeanDefinition,BeanDefinitionRender的呢?查看该类并没有香瓜的代码,
仅包含多个构造的重载方法,还有这个定位资源文件的方法 getResourceByPath(....);
那么只有向他的父类找答案了! 在 AbstractRefreshableWebApplicationContext 中找到了答案! 看看FileSystemXmlApplicationContext的继承关系
查看到AbstractRefreshableWebApplicationContext类的时候发了问题看一下refreshBeanFactory()方法吧!
该方法创建了 DefaultListableBeanFactory beanFactory = createBeanFactory(); 一个IOC 容器用来承载解析的BeanDefinition,容器有了那么BeanDefinition,和BeanDefinitionRender在哪里呢 ?
回想一下文章开始的时候创建IOC的代码 创建好了工厂之后接着做了什么操作,ok现在是Resource,BeanFactory 接着就该BeanDefinitionRender( factory ) ;,还有他的loadBeanDefinitions(resource);
就可以完成BeanDefinition的定位,载入了。这里依然是 loadBeanDefinitions(beanFactory);
是不是和刚才我们自己获取很相近呢? 原来BeanDefinitionRender,BeanDefinition等都是在父类中执行的载入Bean 的操作当然这是合理的因为对于bean的定位来说不同的只是文件的路径也就是path用说不
同而已,那么具体的路径交给具体的子类来实现就ok了,由子类自己来确定使用的资源。
2:BeanDefinition的载入,解析过程
FileSystemXmlApplicationContext.refresh();方法初始化BeanDefinition的入口方法。该方法会调用AbstractRefreshableApplicationContext中的refreshBeanFactory();方法完成 容器的创建 BeanDefinitionRender的初始化BeanDefinition载入等操作
在refreshBeanFactory()方法中会调用 loadBeanDefinitions(beafactory); 该方法由根据不同的具体实现调用不同。此处调用的是 AbstractXmlApplicationContext中的 loadBeanDefinitions(beafactory);具体实现
最后调用loadBeanDefinitions(XmlBeaDefinitionRender);来载入bean的操作,调用了一系列 loadBeanDefinitions()方法;虽然参数不一样但是不注意的话容易出错,具体解析xml的方法是 XmlBeaDefinitionRender中的doLoadBeanDefinitions(InputSource , Resource ) ;方法完成bean的载入,解析操作。
spring 在何时将解析的bean信息封装成了自己的 BeanDefinition对象呢?
这是在BeanDefinitionDocumentRender类中执行的通过 proccessBeanDefinitions( Elelment elt , BeanDefinitionParserDelegate delegate );
最终处理beanDefinition是由BeanDefinitionParserDelegate对象来执行的 处理完成后会产生一个BeanDefinitionHolder对象该对象包涵了BeanDefinition信息还有一些额外信息比如别名等信息
具体的标签解析是调用该类中的 parseBeanDefinitionElement(...) ,parseProppertyElements()....等parse方法进行的xml解析在该类中源码体现就不细说了。
完成解析后就得到了DeanDefinitionHolder对象就得到了BeanDefintion的信息。就此bean的载入就完成了!
3:将已经解析好的BeanDefinition注册到Ioc容器中去.
这一步就是将上面解析得到的beanDefinition对象放到一个map中去.此时的beanDefinition已经可以使用了但是依赖关系尚未完成。