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. Spring(3.2.3) - Beans(10): 生命周期

    Spring 容器可以管理 singleton 作用域 Bean 的生命周期,容器能够跟踪 Bean 实例的创建.销毁.管理 Bean 生命周期行为主要有两个时机: 注入 Bean 的依赖关系之后 即 ...

  2. Nginx - Configuration File Syntax

    Configuration Directives The Nginx configuration file can be described as a list of directives organ ...

  3. 【TOMCAT】Tomcat gzip压缩传输数据

    概述 由于我们项目的三维模型文件非常大,为了提高传输速度,在服务端对其做zip压缩处理非常有必要,能够极大的提高传输速度. 配置 首先需要修改web.xml中请求的数据文件的mime类型的mappin ...

  4. 第十二篇、Swift_Sqlite的使用

    import UIKit class SQLiteManager: NSObject { private static let manager: SQLiteManager = SQLiteManag ...

  5. Js中的运算符

    运算符 运算符:就是可以运算的符号 比如 + .-.*./ 运算符包括: 算术运算符 比较运算符 逻辑运算符 赋值运算符 字符串运算符 1.算术运算符 +.-.*./.%(求余数).++.-- ++: ...

  6. 产品经理常用工具Axure、Visio、Mindmanager使用解析(摘)

    如果想表现产品的业务流程,那么我建议使用Visio来绘制流程图.如果想表现产品的页面图文布局和页面的跳转关系,我建议使用axure.如果想表现产品的信息架构,我建议使用Mindmanager或Xmin ...

  7. Poj OpenJudge 百练 2602 Superlong sums

    1.Link: http://poj.org/problem?id=2602 http://bailian.openjudge.cn/practice/2602/ 2.Content: Superlo ...

  8. [转]mysql-5.6.17-win32免安装版配置

    1. 下载mysql-5.6.17-win32:官网下载地址百度 2. 解压到自定义目录,我这里演示的是D:\wamp\mysql\ 3. 复制根目录下的my-default.ini,改名为my.in ...

  9. c#怎么获取当前页面的url

    Request.ApplicationPath: /testwebRequest.CurrentExecutionFilePath: /testweb/default.aspxRequest.File ...

  10. 【ZeroMQ】消息模式

    1.请求/应答模式(REP/REQ) 该模式特征: 服务器使用REP类型套接字而客户端使用REQ类型套接字 客户端发送请求和接收答复,而服务器则接收请求并发送答复 客户端可以连接到一个或多个服务器.在 ...