javascript
06.Spring 资源加载 - ResourceLoader
基本概念
ResourceLoader 接口,在 Spring 中用于加載資源,通過它可以獲取一個 Resouce 對象。
內部構造
首先來看它的接口定義:
public interface ResourceLoader {// 從 classpath 加載資源時的前綴 String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX; // 關鍵-> 取得 Resource 對象,即獲取資源 Resource getResource(String location); ClassLoader getClassLoader(); }再來看它的繼承關系,如下所示:
-
DefaultResourceLoader?: 作為 ResourceLoader 接口的直接實現類,該類實現了基本的資源加載功能,可以實現對單個資源的加載。
-
ResourcePatternResolver?:該接口繼承了 ResourceLoader,定義了加載多個資源的方法, 可以實現對多個資源的加載。
DefaultResourceLoader
上面介紹過該類通過實現 ResourceLoader 接口實現了加載單個資源的功能。它的子類通過繼承它來實現具體的資源訪問策略。下面來探究下該類如何加載單個資源:
public Resource getResource(String location) {Assert.notNull(location, "Location must not be null");// ① 是否以"/" 開頭if (location.startsWith("/")) { return getResourceByPath(location); } // ② 是否以"classpath:" 開頭,若是則表示該資源類型為 ClassPathResource else if (location.startsWith(CLASSPATH_URL_PREFIX)) { return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader()); } else { try { // ③若都不是,則當成 UrlResource 來處理 URL url = new URL(location); return new UrlResource(url); }catch (MalformedURLException ex) { // 若不是 UrlResource,則仍當作 ① 情況來處理 return getResourceByPath(location); } } }觀察代碼,發現在拿到資源的路徑?loaction?后,會根據 location 的形式分成三種情況來處理:
-
以 “/” 開頭:默認調用類中的?getResourceByPath?方法處理。它的子類通過重寫該方法實現不同形式的資源的訪問。
-
以 “classpath:” 開頭:當成?ClassPathResource?資源對待。
-
其他情況: 當成?UrlResource?資源對待,如果訪問資源拋出異常,則調用 getResourceByPath 來完成資源的訪問。
ResourcePatternResolver
該接口繼承自 ResourceLoader 接口,在其基礎上增加了同時對多個資源的訪問。首先來看它的接口定義:
public interface ResourcePatternResolver extends ResourceLoader { String CLASSPATH_ALL_URL_PREFIX = "classpath*:"; // 例如使用 ant 風格的路徑,匹配路徑下的多個資源 Resource[] getResources(String locationPattern) throws IOException; }1.PathMatchingResourcePatternResolver
該類是 ResourcePatternResolver 接口的直接實現類,它是基于模式匹配的,默認使用AntPathMatcher 進行路徑匹配,它除了支持 ResourceLoader 支持的前綴外,還額外支持?“classpath*”?,下面來探究下該類是如何實現對多個資源的訪問。
public Resource[] getResources(String locationPattern) throws IOException {Assert.notNull(locationPattern, "Location pattern must not be null");// 是否以 "classpath*:" 開頭 if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) { // 通過 getPathMatcher 方法取得 PathMatcher ,默認只有 AntPathMatcher 一個實現類 // 通過 isPattern 方法判斷 "classpath*:" 之后的路徑是否包含 "*" 或 "?" if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) { // 關鍵 -> 找到所有匹配路徑(ant 風格)的資源 return findPathMatchingResources(locationPattern); }else { // 關鍵 -> 通過類加載器查找 return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length())); } }else { int prefixEnd = locationPattern.indexOf(":") + 1; // 判斷資源路徑 ":" 之后的部分是否包含 "*" 或 "?" if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) { return findPathMatchingResources(locationPattern); }else { // 若不存在表示是單個資源,則通過從構造函數傳入的 ResourceLoader 取得 return new Resource[] {getResourceLoader().getResource(locationPattern)}; } } }觀察代碼:
-
該方法首先會去判斷資源路徑是否是類路徑下的資源(以 “classpath*:” 開頭),然后再去判斷路徑是否允許存在多個匹配的資源(路徑中包含 “*” 或 “?”)。
-
只要資源路徑允許多個匹配的資源,就會通過 findPathMatchingResources 方法尋找所有的匹配資源;
-
若資源路徑只存在單個匹配,則通過類加載器尋找類路徑下的資源(findAllClassPathResources) ,其他資源則通過 ResourceLoader 的 getResource 方法獲取。
2.ApplicationContext
通過上面的繼承關系圖可知,該接口繼承了 ResourcePatternResolver 接口,說明它也集成了對對單個或多個資源的訪問功能。
當 Spring 需要進行資源訪問時,實際上并不需要直接使用 Resource?實現類,而是調用?getResource?方法來獲取資源。
當通過 ApplicationContext 實例獲取 Resource 實例時,它將會負責選擇具體的 Resource 的實現類。代碼如下:
//通過 ApplicationContext訪問資源Resource res = ctx.getResource("some/resource/path/myTemplate.txt);從上面代碼中無法確定 Spring 將哪個實現類來訪問指定資源,Spring 將采用和 ApplicationContext 相同的策略來訪問資源。也就是說:如果 ApplicationContext 是 FileSystemXmlApplicationContext,res 就是 FileSystemResource 實例;如果 ApplicationContext 是 ClassPathXmlApplicationContext,res 就是 ClassPathResource 實例;如果 ApplicationContext 是 XmlWebApplicationContext,res 是 ServletContextResource 實例。
也就是說 ApplicationContext 將會確定具體的資源訪問策略,從而將應用程序和具體的資源訪問策略分離開來,這就體現了策略模式的優勢。
參考
- https://www.ibm.com/developerworks/cn/java/j-lo-spring-resource/
轉載于:https://www.cnblogs.com/moxiaotao/p/9349532.html
總結
以上是生活随笔為你收集整理的06.Spring 资源加载 - ResourceLoader的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BZOJ4539: [Hnoi2016]
- 下一篇: selenium自动化测试多条数据选择第