Spring如何解析XML文件——Spring源码之XML初解析

首先,在我的这篇博客中已经说到容器是怎么初步实现的,并且要使用XmlBeanDefinitionReader对象对Xml文件进行解析,那么Xml文件是如何进行解析的,将在这片博客中进行一些陈述.


数据准备阶段

准备的目的是封装resource参数,目的是为了考虑到Resource可能存在编码要求的情况,其次,通过SAX读取XML文件的方式来准备InputSource对象,最后将参数传递到最核心的实现部分doLoadBeanDefinitions(inputSource,encodedResource.getResource())

封装Resource

调用XmlBeanDefinitionReaderloadBeanDefinitions(Resource resource)方法时,首先将resource对象进行再次封装成EncodedResource,查看源码可以发现里面增加了字符集和编码的封装,从命名上来看也可以体现出来,将资源封装完成后,就调用重载的同名函数loadBeanDefinitions(EncodedResource resource)进行正式的解析.

数据准备操作

在重载方法里面首先通过Set<EncodedResource> currentResources属性来记录已经加载的资源,其次,从EncodedResource对象中获取封装好的Resource对象,并获取其inputStream,将获取到的输入流与SAX解析的InputSource绑定,接下来就进入到了核心的实现部分:doLoadBeanDefinitions(inputSource,encodedResource.getResource())

核心实现

核心部分有两个关键步骤:

  1. 调用doLoadDocument(inputSource.resource)方法获取Document
  2. 根据返回的Document信息注册Bean信息

这两个步骤支持着整个Spring容器部分的实现基础

获取Document

进入方法体后,将Document的创建交给DefaultDocumentLoader documentLoader属性的loadDocument()方法,该方法声明如下:

Document loadDocument(
			InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware)
			throws Exception;

调用情况:

documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware())
  • InputSource:SAX解析需要使用到的对象

  • EntityResolver:它的作用是项目本身就可以提供一个如何寻找DTD声明的方法,由程序来实现寻找DTD声明的过程,将DTD文件放到项目中某处,在实现时直接将此文档读取并返回给SAX即可,避免了必须通过网络来寻找相应的声明.

在这个接口中定义了一个方法

InputSource resolveEntity (String publicId,String systemId)
        throws SAXException, IOException;

如果解析的验证模式是XSD:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd>

那么.此时得到的两个参数值分别是:

publicId:null
systemId:http://www.springframework.org/schema/beans/spring-beans.xsd

如果解析的验证模式是DTD:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN 2.0//EN" "http://www.Springframework.org/dtd/Spring-beans-2.0.dtd"

那么,此时得到的两个参数值分别是:

publicId😕/Spring//DTD BEAN 2.0//EN
systemId:http://www.Springframework.org/dtd/Spring-beans-2.0.dtd

而对于不同的验证模式,Spring使用了不同的解析器,当使用DTD验证时,Spring会截取后面的*.dtd,并直接到当前目录去寻找,当使用XSD验证时,Spring会到META-INF/Spring.schemas文件中去匹配相应的systemId并加载对应的XSD文件

  • validationMode:验证模式

首先,为了保证XML文件的正确性,有常见两种验证模式:DTDXSD

两种验证模式的区别

我对这两种的区别目前还不是很详细,只能简略的给出定义,但我看到的最直观的区别是,DTD验证需要单独写出一个标签<!DOCTYPE ...>,而XSD验证会将信息写入<beans xmlns="...">结点

DTD

DTD(Document Type Definition)即文档类型定义,是一种保证XML文档格式正确的有效方法,可以通过比较XML文档和DTD文件来看文档是否符合规范.

XSD

XML Schema语言就是XSD(XML Schema Definition),描述了XML文档的结构,可以用一个指定的XML Schema来验证XML文档,以检查文档是否符合要求.

验证模式的读取

验证模式的读取非常简单,在getValidationModeForResource(resource)方法中先获取当前设定的验证模式是不是自动选择,源码中是这么解释的since we cannot find a clear indication,当找不到一个确切的验证模式时,采用这种方式,然后判断当前resource对象中采用的是什么验证模式,通过检索字符串的方式,当存在DOCTYPE的时候,就采用DTD验证模式,否则采用XSD验证模式

  • namespaceAware:一个布尔值,默认为false,在前面可以看到,在使用XSD验证的时候会有xmlns="",其实就是XML namespace的缩写,可以有多个命名空间,如果使用的是XSD解析,将会把这个值改为true

解析并注册BeanDefinitions

在上一步得到Docment对象之后,调用registerBeanDefinitions(Document doc,Resource resource)

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
        //创建对象
		BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
		//记录当前已经加载的数量
		int countBefore = getRegistry().getBeanDefinitionCount();
		//加载并注册
		documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
		//返回本次加载的个数
		return getRegistry().getBeanDefinitionCount() - countBefore;
	}

而在调用documentReader对象方法中,才开始进行正式的解析工作

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
		this.readerContext = readerContext;
		logger.debug("Loading bean definitions");
		Element root = doc.getDocumentElement();
		doRegisterBeanDefinitions(root);
	}

解析的工作全权交给doRegisterBeanDefinition(root)方法实现,这样XML文件就正式进入了解析步骤,至于怎么解析的,博主将慢慢学习并写入后续博客.

posted @ 2017-05-12 00:32  墨倾辰  阅读(9443)  评论(0编辑  收藏  举报