Spring源码解析 第二章、容器的基本实现

2.7 获取Document

之前我们探讨经过获取完了XML的验证模式之后,就会加载XML文件,获取对应的Doucment对象。之间代码追溯的了

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

XmlBeanFactoryReader对于获取document就没有亲自亲为了,this.documentLoader其实是DefaultDocumentLoader类执行的loadDocument() 在这里的方法返回的document,看看这个方法怎么返回的一个document

public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
		ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {

		DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
		if (logger.isTraceEnabled()) {
			logger.trace("Using JAXP provider [" + factory.getClass().getName() + "]");
		}
		DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
		return builder.parse(inputSource);
	}

这部分的代码也不用描述太多的内容,因为是通过SAX解析的XML文档套路大致都差不多,同样首先创建一个DocumentBuilderFactory,再通过DocumentBuilderFactory创建DocumentBuilder,进而解析inputSource来返回Document对象。SAX解析XML的步骤:1.  获取SAX解析器工厂的实例 2. 获取SAX解析器的实例 3. 解析调用parse方法(File\InputSreme)

2.7.1EntityResolver的用法

SAX解析一个Xml,首先是获取该XML文档上的声明,根据声明寻找相应的DTD声明,并且进行认证。默认的寻找规则是通过网络(实际上通过声明的DTD的URI地址)来下载相应的DTD声明,并且进行认证。下载过程可能很漫长并且容易出错,而且网络中断的情况下,这里会报错。所以......

EntityResolver作用:让项目本身就可以提供给一个如何寻找DTD声明的方法,即由程序寻找DTD声明的过程,比如我们将DTD声明放在项目中的某一个位置,在实现时直接将此文档读取并且返回给SAX即可。这样就避免了通过网络来寻找相应的声明。

entityResolver接口的声明的方法   InputSource resolveEntity(String publicId,String systemsId)

我们在解析验证模式的时候,配置文件的XSD与DTD的两个参数不同。我们看一下entityResolver接口的实现方法

public 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类截取systemId最后的xx.dtd,然后去当前路径下寻找。

public class BeansDtdResolver implements EntityResolver {

	private static final String DTD_EXTENSION = ".dtd";

	private static final String DTD_NAME = "spring-beans";

	private static final Log logger = LogFactory.getLog(BeansDtdResolver.class);


	@Override
	@Nullable
	public 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.isTraceEnabled()) {
						logger.trace("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;
	}


	@Override
	public String toString() {
		return "EntityResolver for spring-beans DTD";
	}

}

而加载XSD类型的PluggableSchemaResolver类默认到META-INF/Spring.schemas文件中找到的systemid所对应的XSD文件来加载

public 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) {
			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.isTraceEnabled()) {
						logger.trace("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
					}
					return source;
				}
				catch (FileNotFoundException ex) {
					if (logger.isDebugEnabled()) {
						logger.debug("Could not find XML schema [" + systemId + "]: " + resource, ex);
					}
				}
			}
		}
		return null;
	}

猜你喜欢

转载自blog.csdn.net/qq_39705793/article/details/83818837