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.
最後,感謝閱讀,如有錯誤之處,請不吝指正。

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