1.1 何为 EntityResolver :

官方解释: 如果SAX应用程序叙事实现自定义处理外部实体,则必须实现此接口,

并使用setEntityResolver方法向SAX 驱动器注册一个实例.

也就是说,对于解析一个xml,sax

首先会读取该xml文档上的声明,根据声明去寻找相应的dtd定义,以便对文档的进行验证,
默认的寻找规则,(即:通过网络,实现上就是声明DTD的地址URI地址来下载DTD声明),
并进行认证,下载的过程是一个漫长的过程,而且当网络不可用时,这里会报错,就是应为相应的dtd没找到,

1.2 EntityResolver 的作用就是项目本身就可以提供一个如何寻找DtD 的声明方法,

即:由程序来实现寻找DTD声明的过程,比如我们将DTD放在项目的某处在实现时直接将此文档读取并返回个SAX即可,这样就避免了通过网络来寻找DTD的声明

1.3 首先看看EntityResolver 接口声明的方法.

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

这里,他接收2个参数,publicId ,systemId ,并返回一个InputStream对象,
这里我们以特定的文件来讲解;

1.3.1  如果我们在解析验证模式为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-2.5.xsd">
...
</beans>

读取得到以下参数,

publicId : null

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

1.3.2 如果我们解析的是DTD的配置文件;

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

读取得到以下参数:

publicId : -//SPRING//DTD BEAN//EN

systemId : http://www.springframework.org/dtd/spring-beans.dtd

之前已经提到过,默认的寻找规则,(即:通过网络,实现上就是声明DTD的地址URI地址来下载DTD声明),这样才会造成延迟,用户体验也不好,一般的做法是将验证文件放在自己的工程里面,

那么怎么做才能将这个Url转换为自己工程里对应的文件呢?我们已加载DTD文件为例看看Spring中是如通过getEntityResolver() 对  EntityResolver 的获取,

1.4  DelegatingEntityResolver

我们知道Spring中使用DelegatingEntityResolver 类为 EntityResolver的实现类,

EntityResolver 的实现方法如下

 @Override
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
if (systemId != null) {
// 如果是DTD从这里开始
if (systemId.endsWith(DTD_SUFFIX)) {
return this.dtdResolver.resolveEntity(publicId, systemId);
}
// 如果是XSD从这里开始
else if (systemId.endsWith(XSD_SUFFIX)) {
// 通过调用META-INF/Spring.schemas解析
return this.schemaResolver.resolveEntity(publicId, systemId);
}
}
return null;
}

我们可以看到,对不同的验证模式,Spring用了不同的解析器,这里简单描述一下原理,

1.4.1  BeanDtdResolver 

比如加载DTD类型的 BeanDtdResolver 的 resolveEntity是直接截取systemId最后的xxx.dtd ,然后去当前路径下寻找,代码如下:

 @Override
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Trying to resolve XML entity with public ID [" + publicId +
"] and system ID [" + systemId + "]");
}
//截取systemId最后的xxx.dtd
if (systemId != null && systemId.endsWith(DTD_EXTENSION)) {
int lastPathSeparator = systemId.lastIndexOf("/");
for (String DTD_NAME : DTD_NAMES) {
int dtdNameStart = systemId.indexOf(DTD_NAME);
if (dtdNameStart > lastPathSeparator) {
String dtdFile = systemId.substring(dtdNameStart);
if (logger.isTraceEnabled()) {
logger.trace("Trying to locate [" + dtdFile + "] in Spring jar");
}
try {
Resource resource = new ClassPathResource(dtdFile, getClass());
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found beans DTD [" + systemId + "] in classpath: " + dtdFile);
}
return source;
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not resolve beans DTD [" + systemId + "]: not found in class path", ex);
}
} }
}
}

1.4.2 PluggableSchemaResolver 

而加载XSD类型的PluggableSchemaResolver 类的 resolveEntity 是默认到META-INF/Spring.schemas文件中找到systemid 对应的XSD文件并加载代码如下

 @Override
public InputSource resolveEntity(String publicId, String systemId) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Trying to resolve XML entity with public id [" + publicId +
"] and system id [" + systemId + "]");
} if (systemId != null) {
//获取 systemId 对应的XSD文件
String resourceLocation = getSchemaMappings().get(systemId);
if (resourceLocation != null) {
Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
try {
InputSource source = new InputSource(resource.getInputStream());
source.setPublicId(publicId);
source.setSystemId(systemId);
if (logger.isDebugEnabled()) {
logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
}
return source;
}
catch (FileNotFoundException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Couldn't find XML schema [" + systemId + "]: " + resource, ex);
}
}
}
}
return null;
}

SAX EntityResolver 的作用的更多相关文章

  1. sax解析xml,验证格式并支持自定义标签

    一.sax简介 SAX是事件驱动型的XML解析方式.顺序读取XML文件,生成事件,传播到用户定义的回调方法中来处理XML文件. 优点: 分段处理xml,而不是将整个xml一次加载进内存,内存占用少,速 ...

  2. SAX - DefaultHandler

    org.xml.sax.helpers.DefaultHandler 实现了 org.xml.sax.EntityResolver.org.xml.sax.DTDHandler.org.xml.sax ...

  3. XML学习记录1-复习SAX,DOM和JAXB

    对xml文档的解析常见的有JDK中的sax,dom,jaxb,stax和JAVA类库JDOM和DOM4J,下面先说说前三个. Java中解析XML的工具很多,像JDOM,DOM4J等,但Java标准库 ...

  4. XmlBeanFactory的Bean注册

    Spring将bean从配置文件到加载到内存中的全过程: BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFac ...

  5. spring源码深度解析-1核心实现

    xml配置文件的读取:1:通过集成字AbstractBeanDefinitionReader中的方法,来使用ResourceLoader将资源文件路径转换为对应的Resource文件2:通过Docum ...

  6. 【死磕 Spring】----- IOC 之 获取 Document 对象

    原文出自:http://cmsblogs.com 在 XmlBeanDefinitionReader.doLoadDocument() 方法中做了两件事情,一是调用 getValidationMode ...

  7. Spring源码学习笔记1

    1.Spring中最核心的两个类 1)DefaultListableBeanFactory XmlBeanFactory继承自DefaultListableBeanFactory,DefaultLis ...

  8. 【Spring源码分析系列】加载Bean

    /** * Create a new XmlBeanFactory with the given input stream, * which must be parsable using DOM. * ...

  9. spring源码学习之容器的基本实现

    最近想拿出一部分时间来学习一下spring的源码,还特意买了一本书结合来看,当然主要是学习并跟着作者的思路来踏上学习spring的源码的道路,特意在此记录一下,<spring源码深度解析> ...

随机推荐

  1. Web.config加密和解密

    在系统部署的时候,大家都会遇到关于用户凭证的安全性问题,而对于数据库连接的相关的信息,有些时候客户也需要我们对其加密,防止信息泄露,在此将加密和解的方法记录于此: 首先用管理员的权限启动cmd命令窗口 ...

  2. Git CMD - checkout: Switch branches or restore working tree files

    命令格式 git checkout [-q] [-f] [-m] [<branch>] git checkout [-q] [-f] [-m] --detach [<branch&g ...

  3. Google推Android新开发语言Sky:流畅度 秒iOS

    Dart初衷 作为当前市占率最高的智能手机操作系统,Android平台正在吸引着越来越多的开发者. 不过,对用户而言,Android的体验还不够完善,卡顿的情况时有发生.再深入点理解,许多应用的帧率达 ...

  4. MSSQL AlwaysOn中的“主角色中的连接”和“可读辅助副本”初探

    一.开篇 在进行配置只读路由的时候,需要进行配置可用性组中的可用性副本,如下如所示: 每一项都是啥意思可以看看这个链接 https://msdn.microsoft.com/zh-cn/library ...

  5. sql中的触发器、视图、事务

    ·触发器(trigger) [触发器本质上还是一个存储过程,只不过不是用exe来调用执行,而是通过增删改数据库的操作] [触发器只对增.删.改有效] 触发器的格式 (instead of与for的区别 ...

  6. Oracle中NVARCHAR2字符集不匹配问题

    Oracle中在做字符匹配时 遇到 NVARCHAR2 类型时报错,提示 字符集不匹配. 对使用 NVARCHAR2 的地方,需要对字段进行字符转换,加上 to_char(nvarchar2 字段) ...

  7. Objective-C 【单个对象内存管理(野指针&内存泄露)】

    ------------------------------------------- 单个对象内存管理 (1)野指针 ①定义了一个指针变量,但是并没有赋初值,它随机指向一个东西 ②某指针变量指向的内 ...

  8. 委托[delegate]_C#

    委托(delegate): 委托声明定义了一种类型,它用一组特定的参数以及返回类型来封装方法.对于静态方法,委托对象封装要调用的方法.对于实例方法,委托对象同时封装一个实例和该实例上的一个方法.如果您 ...

  9. javascript笔记——点击按钮(或超链接)如何跳转到另外一个页面并执行目标页面的js函数

    页面跳转同时执行js代码$(function(){});url参数传递 标题的前半部分其实不必赘述,按钮也可以换成超链接.. 假设是需要在A页面上的一个按钮,点击后跳转到B页面,传一些参数后且并B页面 ...

  10. HTTP Error 500.21解决方案

    Windows 7 IIS (HTTP Error 500.21 - Internal Server Error)解决方案   今天在测试网站的时候,在浏览器中输入http://localhost/时 ...