曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上) (2)

输出如下:

21:38:19.638 [main] INFO o.s.bootstrap.sample.XmlSimpleUse - root is [f:table: null] 21:38:19.653 [main] INFO o.s.bootstrap.sample.XmlSimpleUse - ele:[f:name: null] 21:38:19.653 [main] INFO o.s.bootstrap.sample.XmlSimpleUse - ele:[f:width: null] 21:38:19.653 [main] INFO o.s.bootstrap.sample.XmlSimpleUse - ele:[f:length: null] 21:38:19.654 [main] INFO o.s.bootstrap.sample.XmlSimpleUse - ele:[t:abc: null]

大家可以看上面的demo代码,没有依赖任何spring的类,基本还原了spring解析xml时的大体过程,在spring中多出来的细节部分,主要有两处:

自定义entityResolver

docBuilder.setEntityResolver,这个部分,我们上面是默认实现。

大家看我们前面的xml,有一定了解的同学可能知道,前面定义了两个namespace,语法一般是下面这样的:

xmlns:namespace-prefix="namespaceURI"

所以,我们这边的两个namespace,前缀分别是f、t,内容分别是:

但是,我们一般xml文件是有格式要求的,比如spring里,比如这个命名空间下,可以定义什么元素,这都是定死了的:

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

那,这个约束是在哪里呢?在namespaceURI 对应的dtd/xsd等文件中。

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

像上面截图这样,就是:

这一句,定义一个命名空间 xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans // 下面这个,你要当成key/value来理解,key就是:, //value,就是对应的xsd文件 http://www.springframework.org/schema/context/spring-context.xsd"

有了上面的基础知识,再来说那个接口:

public interface EntityResolver { // 一般传入的systemId即为后边这样的: public abstract InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException; }

这个接口呢,就是让我们自定义一个方法,来解析外部xml实体,一般传入的参数如下:

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

即,publicId为null,systemId为xsd的uri,这个uri一般是可以通过网络获取的,比如:

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

但是,spring是自定义了自己的entityResolver,实现类为:org.springframework.beans.factory.xml.ResourceEntityResolver。

这个类,会在本地寻找对应的xsd文件,主要逻辑就是去查找classpath下的META-INF/spring.schemas,我们可以看看spring-beans包内的该文件:

曹工说Spring Boot源码(7)-- Spring解析xml文件,到底从中得到了什么(上)

spring为什么要自定义EntityResolver呢,spring为啥要在本地找呢,原因是:

如果不自定义,jdk的dom解析类,就会直接使用这个东西,去作为URL,建立socket网络连接来获取。而部分环境,比如生产环境,基本是外网隔离的,你这时候是没办法去下载这个xsd文件的,岂不是就没法校验xml文件的语法、格式了吗?

所以,spring要将这个外部的xsd引用,转为在classpath下的查找。

自定义元素解析逻辑

这部分,大家再看下之前的骨架代码:

Document document = docBuilder.parse(inputSource); Element root = document.getDocumentElement(); log.info("root is {}",root); NodeList nodeList = root.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node node = nodeList.item(i); //遍历每个元素,我们这里只是简单输出 if (node instanceof Element) { Element ele = (Element) node; log.info("ele:{}",ele); } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpfszg.html