Spring 源碼閲讀 01:Resource 資源抽象

語言: CN / TW / HK

攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第18天,點擊查看活動詳情

在 Spring 的核心源碼中,Resource 接口定義了 Spring 對底層資源訪問的抽象,通過實現 Resource 接口,我們可以開發各種資源的訪問能力。以 Spring 自身為例,Resource 的使用非常廣泛,我們可以在源碼中的很多方法或者構造方法中看到 Resource 類型的參數。比如,通過 XML 加載容器配置、從 application.properties 文件讀取 Spring Boot 項目配置信息,都是通過 Resource 接口的實現類來實現對這些文件的訪問的。

Resource 接口

Resource 接口的定義如下:

public interface Resource extends InputStreamSource { boolean exists(); boolean isReadable(); boolean isOpen(); boolean isFile(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; ReadableByteChannel readableChannel() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; String getFilename(); String getDescription(); }

在以上的方法中:

  • exist()isXXX() 方法提供了對資源狀態的判斷;
  • getFile()getURI()getURL() 提供了資源到FileURIURL的轉換;
  • getFilename()getDescription() 提供了一些資源信息的獲取,一般用於日誌信息。

此外,它還繼承了 InputStreamSource 接口:

public interface InputStreamSource { InputStream getInputStream() throws IOException; }

這裏的 getInputStream() 提供了從資源獲取輸入流的方法,每次調用這個方法,都需要返回一個新的輸入流,不過要注意,輸入流不在被使用的時候,一定要記得關閉。

Resource 實現類

在 Spring 中,已經包含了很多 Resource 的實現類,如下是一些常見的 Resource 實現類:

從這些實現類的名稱中,我們就能看出它們分別實現了那些來源的資源訪問。下面我們分別分析一下這幾個實現類:

FileSystemResource

一個 FileSystemResource 可以通過 File 對象或者文件路徑來創建,在 FileSystemResource 類中,有以下三個成員變量:

``` private final String path;

@Nullable private final File file;

private final Path filePath; ```

它們會在構造方法中被初始化,值分別是文件路徑字符串、訪問文件的 File 對象、文件路徑對應的 Path 對象。

當調用 getInputStream() 方法的時候,會通過 File 對象創建一個 InputStream 對象。其他的一些操作也都會在 File 對象上完成。

ByteArrayResource

ByteArrayResource 的名字就可以看出,創建它並不需要外部資源,只需要提供一個 ByteArray 即可。在 ByteArrayResource 中只有兩個成員變量:

``` private final byte[] byteArray;

private final String description; ```

分別代表 byteArray 本身和其描述信息,我們可以在創建對象時給它提供一個描述,如果不提供,默認的描述信息是 resource loaded from byte array,當需要調用 getInputStream() 獲取輸入流的時候,將會得到一個 ByteArrayInputStream。實現方法如下:

@Override public InputStream getInputStream() throws IOException { return new ByteArrayInputStream(this.byteArray); }

ByteArrayResource 比較適用於一些需要用 ByteArray 創建一次性輸入流的地方。

UrlResource

UrlResource 可以使用 URL 創建,也可以使用 URI 創建,可以用來訪問一些需要通過 HTTP 或者 FTP 等訪問的文件和內容。

當調用 getInputStream() 方法獲取數據流的時候,會通過 URL 創建 URLConnection ,然後從中獲取 InputStream 對象,代碼如下:

@Override public InputStream getInputStream() throws IOException { URLConnection con = this.url.openConnection(); ResourceUtils.useCachesIfNecessary(con); try { return con.getInputStream(); } catch (IOException ex) { // Close the HTTP connection (if applicable). if (con instanceof HttpURLConnection) { ((HttpURLConnection) con).disconnect(); } throw ex; } }

ClassPathResource

ClassPathResource 提供了從類路徑訪問資源的方法,創建 ClassPathResource 需要提供一個資源路徑,以及一個類加載器或者一個類對象。我們通常在 Spring 的配置文件中使用 classpath: 作為前綴的資源路徑,都是通過 ClassPathResource 讀取的。

InputStreamResource

我們也可以使用 InputStreamResource 將一個已經創建的 InputStream 封裝成一個 Resource,當通過 getInputStream() 獲取輸入流的時候,會得到我們創建 InputStreamResource 時提供的 InputStream。當沒有其他的 Resource 實現類可以適用當前資源的時候,可以使用它,不過,這個資源的數據流只能被讀取一次。