首先,在我的中已经说到容器是怎么初步实现的,并且要使用XmlBeanDefinitionReader
对象对Xml
文件进行解析,那么Xml
文件是如何进行解析的,将在这片博客中进行一些陈述.
数据准备阶段
准备的目的是封装resource
参数,目的是为了考虑到Resource
可能存在编码要求的情况,其次,通过SAX
读取XML
文件的方式来准备InputSource
对象,最后将参数传递到最核心的实现部分doLoadBeanDefinitions(inputSource,encodedResource.getResource())
封装Resource
调用XmlBeanDefinitionReader
的loadBeanDefinitions(Resource resource)
方法时,首先将resource对象进行再次封装成EncodedResource
,查看源码可以发现里面增加了字符集和编码的封装,从命名上来看也可以体现出来,将资源封装完成后,就调用重载的同名函数loadBeanDefinitions(EncodedResource resource)
进行正式的解析.
数据准备操作
在重载方法里面首先通过Set<EncodedResource> currentResources
属性来记录已经加载的资源,其次,从EncodedResource
对象中获取封装好的Resource
对象,并获取其inputStream
,将获取到的输入流与SAX解析的InputSource
绑定,接下来就进入到了核心的实现部分:doLoadBeanDefinitions(inputSource,encodedResource.getResource())
核心实现
核心部分有两个关键步骤:
- 调用
doLoadDocument(inputSource.resource)
方法获取Document
- 根据返回的
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
:
那么.此时得到的两个参数值分别是:
publicId
:null
systemId
: 如果解析的验证模式是DTD
:
那么,此时得到的两个参数值分别是:
publicId
:-//Spring//DTD BEAN 2.0//EN
systemId
: 而对于不同的验证模式,Spring
使用了不同的解析器,当使用DTD
验证时,Spring
会截取后面的*.dtd
,并直接到当前目录去寻找,当使用XSD
验证时,Spring
会到META-INF/Spring.schemas
文件中去匹配相应的systemId
并加载对应的XSD
文件
validationMode
:验证模式
首先,为了保证XML
文件的正确性,有常见两种验证模式:DTD
、XSD
两种验证模式的区别
我对这两种的区别目前还不是很详细,只能简略的给出定义,但我看到的最直观的区别是,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
文件就正式进入了解析步骤,至于怎么解析的,博主将慢慢学习并写入后续博客.