spring源码深度解析—容器的基本实现,你知多少?( 六 )

这个entityResolver是做什么用的呢 , 接下来我们详细分析下 。 
5.4.1 EntityResolver 的用法 
如果SAX应用程序需要实现自定义处理外部实体 , 则必须实现此接口并使用setEntityResolver方法向SAX驱动器注册一个实例 。也就是说 , 对于解析一个XML , SAX首先读取该XML文档上的声明 , 根据声明去寻找相应的DTD定义 , 以便对文档进行一个验证 , 默认的寻找规则 , 即通过网络(实现上就是声明DTD的URI地址)来下载相应的DTD声明 , 并进行认证 。下载的过程是一个漫长的过程 , 而且当网络中断或不可用时 , 这里会报错 , 就是因为相应的DTD声明没有被找到的原因 
EntityResolver的作用是项目本身就可以提供一个如何寻找DTD声明的方法 , 即由程序来实现寻找DTD声明的过程 , 比如将DTD文件放到项目中某处 , 在实现时直接将此文档读取并返回给SAX即可 , 在EntityResolver的接口只有一个方法声明:
public abstract InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException;它接收两个参数publicId和systemId , 并返回一个InputSource对象 , 以特定配置文件来进行讲解 
(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.xsd">....</beans>则会读取到以下两个参数 
- publicId:null 
- systemId:http://www.Springframework.org/schema/beans/Spring-beans.xsd 
(2)如果解析验证模式为DTD的配置文件 , 代码如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//Spring//DTD BEAN 2.0//EN" "http://www.Springframework.org/dtd/Spring-beans-2.0.dtd">....</beans>读取到以下两个参数 
- publicId:-//Spring//DTD BEAN 2.0//EN 
- systemId:http://www.Springframework.org/dtd/Spring-beans-2.0.dtd 
一般都会把验证文件放置在自己的工程里 , 如果把URL转换为自己工程里对应的地址文件呢?以加载DTD文件为例来看看Spring是如何实现的 。根据之前Spring中通过getEntityResolver()方法对EntityResolver的获取 , 我们知道 , Spring中使用DelegatingEntityResolver类为EntityResolver的实现类 , resolveEntity实现方法如下:
@Override@Nullablepublic InputSource resolveEntity(String publicId, @Nullable String systemId) throws SAXException, IOException { if (systemId != null) { if (systemId.endsWith(DTD_SUFFIX)) { return this.dtdResolver.resolveEntity(publicId, systemId); } else if (systemId.endsWith(XSD_SUFFIX)) { return this.schemaResolver.resolveEntity(publicId, systemId); } } return null;对不同的验证模式 , Spring使用了不同的解析器解析 , 比如加载DTD类型的BeansDtdResolver的resolveEntity是直接截取systemId最后的xx.dtd然后去当前路径下寻找 , 而加载XSD类型的PluggableSchemaResolver类的resolveEntity是默认到META-INF/Spring.schemas文件中找到systemId所对应的XSD文件并加载 , 下面是BeansDtdResolver的源码:
@Override@Nullablepublic InputSource resolveEntity(String publicId, @Nullable 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.endsWith(DTD_EXTENSION)) { int lastPathSeparator = systemId.lastIndexOf('/'); int dtdNameStart = systemId.indexOf(DTD_NAME, lastPathSeparator); if (dtdNameStart != -1) { String dtdFile = DTD_NAME + DTD_EXTENSION; if (logger.isTraceEnabled()) { logger.trace("Trying to locate [" + dtdFile + "] in Spring jar on classpath"); } 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 classpath", ex); } } } } // Use the default behavior -> download from website or wherever. return null;}


推荐阅读