之前提到Spring會將配置問價或者配置類讀取到內存轉換成一個個的Resource實例。然後將Resource解析一個個的BeanDefinitioon.
Resource接口
public interface Resource extends InputStreamSource
Resource繼承於InputStreamSource接口 ,InputStreamSource接口僅僅定義了一個方法,獲取輸入流。Resource定義了對資源的基本操作。判斷資源是否存在,是否可讀,是否打開 ==。
Resource接口體系
EncodedResource類
EncodedResource實現了了InputStreamSource接口,該類的主要作用是 對資源文件的編碼處理。
AbstractResource
該抽象類實現了大量的對Resource方法的默認公共實現。如果要實現自己的Resource,應該繼承該類,而不是實現頂層接口。
ClassPathResource類
提供根據類文件夾訪相對路徑問資源的能力。
FileSystemResource類
提供訪問系統資源的能力,但是JDK自帶的 File類相關,也不錯。
此外,FileSystemResource實現了WritableResource接口,WritableResource接口定義了 對資源寫的能力。那麼回過頭去看Resource接口,僅僅定義了讀取資源的能力。
體驗FileSystemResource
在 項目中創立一個文件。test.txt
然後利用Spring的FileSystemResource進行讀寫操作。
public class ResourceDemo {
public static void main(String[] args) throws IOException {
FileSystemResource fileSystemResource = new FileSystemResource(
"E:\\mooc\\熟悉Spring源碼\\src\\main\\java\\com\\fuyouj\\demo\\resource\\test.txt");
File file = fileSystemResource.getFile();
System.out.println(file.length());
//獲取輸出流
OutputStream outputStream = fileSystemResource.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("你好");
bufferedWriter.flush();
outputStream.close();
bufferedWriter.close();
}
}
可以看到,爲了訪問不同的資源,要通過不同的Resource實現類,那麼可以不顯示使用實現類的情況下,就能夠訪問不同的資源。答案是肯定的,我們平時使用的時候就沒有顯示用這些實現類。
Spring不僅僅帶classpath:,file前綴的資源,還能解析Ant風格的路徑。
Ant風格我們也經常用到。
這種自動適配所有資源的能力是 ResourceLoader賦予的。
ResourceLoader
ResourceLoader實現不同的Resource加載策略,按需返回不同的類型的Resource.
DefaultResourceLoader
DefaultResourceLoader實現了ResourceLoader接口,其中的getResource
就是根據地址的不同 返回不同的Resource實例。
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
if (location.startsWith("/")) {
return getResourceByPath(location);
}
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// Try to parse the location as a URL...
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
ResourcePatternResolver
回到ResouceLoader接口,觀察裏面的
Resource getResource(String location);
方法發現僅僅支持路徑地址的解析,而不能滿足Ant風格,所以 ResourcePatternResolver正是提供了這樣的能力。
繼續觀察類圖,
可以看到熟悉的 Application容器接口,因此可以說,Spring中的容器具有解析任意資源的能力。