spring 的getEntityResolver做了哪些操作

spring在读取配置文件加载bean定义的时候会用到一个方法如下:

	/**
	 * Return the EntityResolver to use, building a default resolver
	 * if none specified.
	 */
	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;
	}

方法注释大致意思是创建一个可以使用的EntityResolver ,如果没有指定的话创建一个默认的。
那么这个EntityResolver 到底是什么呢?
xml解析的时候会遇到你所配置的xml格式是否符合规范的问题,而sax解析,可以通过你在xml的声明上配置的publicid 和 连接地址获取配置文件需要执行的一些规范,考虑到网络下载不稳定以及断网等问题,大多数框架会在自己内部jar包内放一份文件,然后自定义类实现EntityResolver 接口,这样代码运行先从本地尝试获取规范文件,获取不到才会从网络下载,具体可以这篇博客
回到上面的方法,可以看到,spring内部有两种方式创建EntityResolver,但是点进源码你会发现,
在这里插入图片描述
ResourceEntityResolver继承了DelegatingEntityResolver,重写的方法如下

@Override
	@Nullable
	public InputSource resolveEntity(String publicId, @Nullable String systemId) throws SAXException, IOException {
		InputSource source = super.resolveEntity(publicId, systemId);
		if (source == null && systemId != null) {
			String resourcePath = null;
			try {
				String decodedSystemId = URLDecoder.decode(systemId, "UTF-8");
				String givenUrl = new URL(decodedSystemId).toString();
				String systemRootUrl = new File("").toURI().toURL().toString();
				// Try relative to resource base if currently in system root.
				if (givenUrl.startsWith(systemRootUrl)) {
					resourcePath = givenUrl.substring(systemRootUrl.length());
				}
			}
			catch (Exception ex) {
				// Typically a MalformedURLException or AccessControlException.
				if (logger.isDebugEnabled()) {
					logger.debug("Could not resolve XML entity [" + systemId + "] against system root URL", ex);
				}
				// No URL (or no resolvable URL) -> try relative to resource base.
				resourcePath = systemId;
			}
			if (resourcePath != null) {
				if (logger.isTraceEnabled()) {
					logger.trace("Trying to locate XML entity [" + systemId + "] as resource [" + resourcePath + "]");
				}
				Resource resource = this.resourceLoader.getResource(resourcePath);
				source = new InputSource(resource.getInputStream());
				source.setPublicId(publicId);
				source.setSystemId(systemId);
				if (logger.isDebugEnabled()) {
					logger.debug("Found XML entity [" + systemId + "]: " + resource);
				}
			}
		}
		return source;
	}

可以看到它先是调用父类的resolveEntity方法获取inputSource ,如果调用父类获取失败,那么首先会获取项目运行的绝对路径,然后判断配置文件里面配置的url是不是用项目绝对路径开头的,如果是的话,说明文件是根据项目名自定义配置的,那么截取绝对路径后面的路径,即相对路径,作为resource,如果上面解码配置文件里面的路径有异常或者无法获取项目路径,就会直接把这个文档配置的systemId作为resource。最后通过resourceLoader
获取inputSource.
上面说到ResourceEntityResolver会调用 DelegatingEntityResolver里面的resolveEntity方法,那么在父类里面这个方法做了什么操作呢?

public class DelegatingEntityResolver implements EntityResolver {

	/** Suffix for DTD files. */
	public static final String DTD_SUFFIX = ".dtd";

	/** Suffix for schema definition files. */
	public static final String XSD_SUFFIX = ".xsd";


	private final EntityResolver dtdResolver;

	private final EntityResolver schemaResolver;
	
	public DelegatingEntityResolver(@Nullable ClassLoader classLoader) {
		this.dtdResolver = new BeansDtdResolver();
		this.schemaResolver = new PluggableSchemaResolver(classLoader);
	}
	
	@Override
	@Nullable
	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;
	}
}

可见DelegatingEntityResolver中封装了两个EntityResolver,一个是代理DTD的BeansDtdResolver,另一个是代理xml schema的PluggableSchemaResolver,resolveEntity方法会根据systemid的后缀判断是用哪个entityResolver校验xml.
最后,感谢阅读,如有错误之处,请不吝指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章