Spring中的Document

本文探讨了Spring如何通过EntityResolver在解析XML配置文件时处理DTD和XSD引用,重点讲解了getEntityResolver方法和EntityResolver在寻找外部实体资源的角色,包括自定义DTD查找和XSD映射到本地资源的过程。
摘要由CSDN通过智能技术生成

上一篇文章已经介绍了Spring中XML的验证方式.接着讲Spring是如何把配置文件解析成Document的.

Document

	@Override
	public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
			ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
		// 1、创建DocumentBuidlerFactory
		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isTraceEnabled()) {
			logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		// 2、通过DocumentBuidlerFactory创建DocumentBuilder
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		// 3、通过DocumentBuilder创建Document
		return builder.parse(inputSource);
	}

因为通过SAX解析XML文档的套路大致都差不多,所以这里不再多说.
但是该方法有一个参数需要注意:entityResolver
这里再贴一遍进入这个方法之前的代码:

protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
		return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,
				getValidationModeForResource(resource), isNamespaceAware());
	}

可以看到entityResolver是通过getEntityResolver来获取的.
那什么是entityResolver?

EntityResolver
官网:如果SAX应用程序需要实现自定义处理外部实体,则必须实现此接口并且使用setEntityResolver方法向SAX驱动器注册一个实体.
也就是说,对于解析一个XML文件,SAX首先读取该XML文档上的声明,根据声明去寻找相应的DTD定义,以便对文档进行一个验证.
而默认的寻找规则是通过网络(就是通过声明的DTD的URI地址)下载相应的DTD声明,并进行认证.但是因为下载的过程中可能因为网络中断或不可用,导致这里报错,因为她会认为你的DTD声明没有被找到.
EntityResolver的作用是项目本身就可以提供一个如何寻找DTD声明的方法,即由程序来实现寻找DTD声明的过程,比如我们把这个DTD文件放到项目中某处,在实现时直接将此文档读取并返回给SAX即可.

下面逐一介绍EntityResolver的获取和使用.
1、getEntityResolver()的代码如下:

	protected EntityResolver getEntityResolver() {
		if (this.entityResolver == null) {
			// Determine default EntityResolver to use.
			ResourceLoader resourceLoader = getResourceLoader();
			if (resourceLoader != null) {
				this.entityResolver = new ResourceEntityResolver(resourceLoader);
			}
			else {
				this.entityResolver = new DelegatingEntityResolver(getBeanClassLoader());
			}
		}
		return this.entityResolver;
	}

2、将URL转化为自己工程中对应的文件地址
先介绍下entityResolver的工作原理
接口方法声明

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

注意这里有两个参数:publicIdsystemId
分别使用两种方式的验证模式进行说明,这两个参数接受值.

  1. XSD模式的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
</project>

那么两个参数的值为:

  • publicId:null
  • systemId:https://maven.apache.org/xsd/maven-4.0.0.xsd
  1. DTD模式的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="xx.xxx.xxx.xxxMapper">
</mapper>

那么两个参数的值为:

  • publicId: -//mybatis.org//DTD Mapper 3.0//EN
  • systemId: http://mybatis.org/dtd/mybatis-3-mapper.dtd

那么Spring是如何把URL转化为自己工程里文件的呢?
根据前面获取entityResolver的代码,可以知道,EntityResolver的实现类中有一个DelegatingEntityResolver.那么看一下这个实现类中的resolveEntity.

public InputSource resolveEntity(@Nullable String publicId, @Nullable String systemId)
			throws SAXException, IOException {
			// 通过上面的原理分析,不管是XSD还是DTD,systemId都不为空
		if (systemId != null) {
			// 判断systemId是否是以dtd后缀结尾
			if (systemId.endsWith(DTD_SUFFIX)) {
				// 如果是则使用 dtdResolver解析dtd,
				// 直接截取systemId最后的xx.dtd,然后去当前路径下寻找
				return this.dtdResolver.resolveEntity(publicId, systemId);
			}
			// 是否是以xsd结尾
			else if (systemId.endsWith(XSD_SUFFIX)) {
				// 如果是则使用schemaResolver解析
				//通过调用META-INF/spring.schemas文件中找到systemid所对应的XSD文件
				return this.schemaResolver.resolveEntity(publicId, systemId);
			}
		}
		// Fall back to the parser's default behavior.
		return null;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值