org.springframework.core.io.Resource 為 Spring API 提供單一控制代碼,處理可能位於檔案、類別路徑項目、URL、Servlet 內容、位元組陣列或已開啟串流中的內容。抽象層描述存取能力,但不會使每個資源都可搜尋、可重複、可寫入或由檔案支援。
Resource 契約
#
Resource 擴充 InputStreamSource。getInputStream() 是基本操作,而 exists()、isReadable()、isOpen()、isFile()、contentLength()、lastModified() 與 getDescription() 等方法會公開能力或中繼資料。
重要實作包括:
ClassPathResource,用於類別載入器或類別相對項目;FileSystemResource與PathResource,用於檔案系統內容;UrlResource,用於 JVM 支援的 URL;ServletContextResource,用於 Web 應用程式路徑;ByteArrayResource,用於可重複的記憶體內位元組;以及InputStreamResource,用於已開啟且通常只能使用一次的串流。
呼叫者擁有 getInputStream() 回傳的每個串流,且必須關閉它。isOpen() 尤其重要:InputStreamResource 包裝已開啟的控制代碼,無法安全地重複讀取,而檔案與位元組陣列資源可以為每次呼叫開啟新的串流。
載入與相對解析 #
ResourceLoader.getResource(String) 會將位置轉換成單一資源。每個 ApplicationContext 都是資源載入器。前綴會選取明確語意:
classpath:com/example/report.html選取類別路徑資源。file:/srv/app/report.html選取檔案系統 URL。https://example.net/schema.json選取 URL 資源。
未加前綴的位置是內容相對位置。ClassPathXmlApplicationContext 會將它解讀為類別路徑位置,FileSystemXmlApplicationContext 會將它解讀為檔案系統位置,而 Web 應用程式內容則將它解讀為 Servlet 內容位置。函式庫程式碼應要求 Resource 或 ResourceLoader,而不是假設單一預設值。
ResourcePatternResolver 將載入擴充至位置模式與多個相符項目;classpath*: 會搜尋所有相符的類別路徑根目錄。Ant 風格萬用字元會透過模式解析套用,而不是透過單一資源 ResourceLoader 契約套用。
注入資源 #
Spring 可以使用周圍的應用程式內容作為載入器,將位置字串轉換為 Resource:
@Component
final class ReportRenderer {
private final Resource template;
ReportRenderer(@Value("${report.template:classpath:reports/daily.html}")
Resource template) {
this.template = template;
}
}建構函式注入會使相依性可見,並讓測試提供 ByteArrayResource。當位置依每次操作變更時注入 ResourceLoader;只有在應用程式刻意接受多個相符項目時,才注入 Resource[] 或 ResourcePatternResolver。
存在性、可重複性與寫入 #
exists() 是探測而非保留;內容可能在開啟前消失。當正確性取決於存取時,請優先開啟資源並處理產生的 IOException。中繼資料操作也可能需要 I/O,而遠端 URL 可能很慢或無法使用。
WritableResource 增加 isWritable() 與 getOutputStream()。FileSystemResource 與 PathResource 實作它,而封裝 JAR 內的類別路徑資源則不實作。需要寫入的程式碼應要求 WritableResource,而不是根據位置字串向下轉型。
可重複性取決於實作。需要兩次走訪的剖析器可以將一次性資源緩衝到 ByteArrayResource,並明確設定大小限制。API 應記錄它們是否開啟一次、重新開啟、保留或關閉串流,讓資源所有權保持明確。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)