Spring源码分析:1.容器的基础XmlBeanFactory

分析以下功能的代码实现:

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactory.xml"));

1.ClassPathResource类的作用

首先分析new ClassPathResource(“beanFactory.xml”),此句是通过ClassPathResource类将beanFactor.xml文件封装为一个具有统一结构的Resource对象(Resource为一接口,提供了一些方法用以检查当前资源是否存在、是否可读。对于不同类型的资源,Resource有着不同的实现。比如对于文件File类型的资源来说,其封装类为FileSystemResource类)。

其中,Resource类继承自InputStream,提供一**getInputStream()**方法以获得InputStream输入流,使得后续处理方法可通过Resource获得beanFactor.xml文件的文本内容(只能获取其字符信息,无法解析其意义,“能读但读不懂”)。

补充:其实Resource中getInputStream()所提供的输入流也是通过jdk的底层方法调用的,其根本就是获得一个输入流来读取文件,和平时的读取操作别无二致。如对于FileSystemResource类,其getInputStream()方法返回的InputStream就是:FileInpurStream(this.file)。

	//**FileSystemResource.java**
	public InputStream getInputStream() throws IOException{
		return new FileInputStream(this.file);
	}

2.解析XML及注册BeanDefinition

得到Resource对象之后,XMLBeanFactory调用一个也十分重要的类:XMLBeanDefinitionReader类的方法this.reader.loadDefinitions(resource)。此句代码便是整个资源加载的切入点,此方法及其嵌套调用的各种方法完成了对XML文件的解析及BeanDefinition的解析和注册。接下来,详细分析此方法的处理过程。

(1)使用EncodedResource类对Resource对象进行封装

当进入XMLBeanDefinitionReader后首先对参数Resource使用EncodedResource类进行封装。对于该Resource对象,采用我们设置的编码方式进行编码,使得后续处理时可以获得我们期望的编码输入流。

(2)获取输入流

从Resource中获取对应的InputStream并构造InputSource。(为了后续使用sax读取XML文件,所有的sax API都从InputSource开始)。

(3)调用函数doLoadBeanDefinitions

通过构造的InputSource实例和Resource实例调用doLoadBeanDefinitions(inputSource,encodedResource.getResource())。其中,此函数的主要逻辑有三部分:

①. 获取XML文件的验证模式(DTD/XSD)

int validationMode=getValidationModeForResource(resource);	//获取文件验证模式

验证模式可手动设定,手动设定后,上述方法得到的验证模式就是该设定值。若无手动设定,则开启自动检测验证模式,使用detectValidationMode()方法,该方法主要检测XML文档中是否包含“DOCTYPE”字符串,包含则使用DTD验证模式,不包含则使用XSD验证模式。另一些细节问题可参照《Spring源码深度解析》P26-P27.

②.获取Document

XmlBeanFactoryReader委托给DocumentLoader去执行,DocumentLoader是个接口,真正调用的是DefaultDocumentLoader。首先创建DocumentBuilderFactory,再通过DocumentBuilderFactory创建DocumentBuilder,进而解析InputSource来返回Document对象。

Document对象介绍:使用上述的解析器后,会将XML文件解析为一结点树,树中各结点对应XML中的一个标签。如根结点就是XML中的根标签< beans>。根结点的子结点对应根标签的子标签,以此类推。Document其实就是对应XML的整个文档。通过根结点可找到所有的子结点,方便后续对结点进行进一步解析。

③解析并注册BeanDefinition

获取Document对象后,XmlBeanDefinitionReader调用:registerBeanDefinitions(Document doc,Resource resource)方法,此方法又委托给单一的类(BeanDefinitionDocument类)进行处理(单一职责模式)。

在实现了BeanDefinitionDocumentReader类接口的DefaultBeanDefinitionDocumentReader的方法registerBeanDefinitions(Document doc, XmlReaderContext readerContext)中提取doc对象的根结点(对应XML的根标签),并将此根结点传入doRegisterBeanDefinitions(Element root)方法,此方法为核心逻辑代码。

在doRegisterBeanDefinition方法中,首先完成的是对Profile属性的处理。Profile属性可以方便的进行切换开发部署环境。接下来,真正开始解析标签,进入parseBeanDefinition(Element root , BeanDefnitionParserDelegate delegate)方法。

parseBeanDefinition()方法完成对结点(标签)的解析。首先检验root是否为默认根标签,若是默认根标签,则遍历其各子结点进行解析(子标签也区分是否为默认标签),若是自定义根标签则转入自定义标签解析方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值