目錄
- 8.1、Spring Resources概述
- 補充:什么是 low-level 資源?
- 1. 文件系統資源
- 2. 類路徑資源
- 3. URL資源
- 4. 內嵌資源
- 5. InputStream資源
- 6. ServletContext資源
- 示例代碼
- 結論
- 8.2、Resource接口
- 8.3、Resource的實現類
- 8.3.1、UrlResource訪問網絡資源
- 1)訪問基于HTTP協議的網絡資源
- 2)在項目根路徑下創建文件,從文件系統中讀取資源
- 8.3.2 ClassPathResource 訪問類路徑下資源
- 1)實驗:在類路徑下創建文件atguigu.txt,使用ClassPathResource 訪問
- 8.3.3、FileSystemResource 訪問文件系統資源
- 8.3.4、ServletContextResource
- 8.3.5、InputStreamResource
- 8.3.6、ByteArrayResource
- 8.4、Resource類圖
- 8.5、ResourceLoader 接口
- 8.5.1、使用演示
- 8.5.3、ResourceLoader 總結
- 8.6、ResourceLoaderAware 接口
- 8.7 應用程序上下文和資源路徑
- 8.8.1、ApplicationContext實現類指定訪問策略
8.1、Spring Resources概述
Java的標準java.net.URL類和各種URL前綴的類無法滿足所有對low-level資源的訪問。
比如:沒有標準化的 URL 實現訪問需要從類路徑或相對于 ServletContext 獲取的資源。并且缺少某些Spring所需要的功能,例如檢測某資源是否存在等。
Spring的Resource聲明了訪問low-level資源的能力。
補充:什么是 low-level 資源?
在Spring框架中,Resource
接口是一個抽象接口,用于統一訪問各種低級別(low-level)的資源。低級別資源指的是那些需要通過底層I/O操作進行讀取和寫入的資源。具體來說,這些資源可以包括:
1. 文件系統資源
- 本地文件:在文件系統中的文件,例如文本文件、配置文件、圖像文件等。
Resource resource = new FileSystemResource("/path/to/file.txt");
2. 類路徑資源
- 類路徑中的資源:通常是項目中的配置文件、靜態資源等,位于類路徑下。
Resource resource = new ClassPathResource("config/application.properties");
3. URL資源
- 網絡資源:通過URL訪問的資源,可以是HTTP、HTTPS、FTP等協議。
Resource resource = new UrlResource("http://example.com/resource.txt");
4. 內嵌資源
- 內嵌在JAR包或WAR包中的資源:通過類路徑訪問的資源,常用于讀取內部配置文件或嵌入式資源。
Resource resource = new ClassPathResource("META-INF/spring.factories");
5. InputStream資源
- 輸入流資源:從輸入流中讀取的資源,通常用于處理非文件系統的流數據。
InputStream inputStream = new ByteArrayInputStream("sample data".getBytes()); Resource resource = new InputStreamResource(inputStream);
6. ServletContext資源
- Web應用程序上下文中的資源:在Web應用的Servlet上下文中訪問資源。
Resource resource = new ServletContextResource(servletContext, "/WEB-INF/config.xml");
示例代碼
下面是一些示例代碼,展示了如何使用Spring的Resource
接口訪問不同類型的資源:
import org.springframework.core.io.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.UrlResource;
import org.springframework.core.io.InputStreamResource;import java.io.IOException;
import java.io.InputStream;public class ResourceExample {public static void main(String[] args) throws IOException {// 1. 訪問文件系統中的資源Resource fileSystemResource = new FileSystemResource("/path/to/file.txt");printResourceContent(fileSystemResource);// 2. 訪問類路徑中的資源Resource classPathResource = new ClassPathResource("config/application.properties");printResourceContent(classPathResource);// 3. 訪問URL中的資源Resource urlResource = new UrlResource("http://example.com/resource.txt");printResourceContent(urlResource);// 4. 訪問輸入流資源InputStream inputStream = new ByteArrayInputStream("sample data".getBytes());Resource inputStreamResource = new InputStreamResource(inputStream);printResourceContent(inputStreamResource);}private static void printResourceContent(Resource resource) throws IOException {try (InputStream is = resource.getInputStream()) {byte[] buffer = new byte[is.available()];is.read(buffer);String content = new String(buffer);System.out.println("Resource content: " + content);}}
}
結論
Spring的Resource
接口提供了一種統一的方式來訪問各種低級別的資源,無論這些資源是本地文件、類路徑資源、URL資源還是輸入流資源。通過使用Resource
接口,開發人員可以輕松地讀取和管理不同類型的資源,提升了代碼的可維護性和靈活性。
8.2、Resource接口
Spring 的 Resource 接口位于 org.springframework.core.io 中。 旨在成為一個更強大的接口,用于抽象對低級資源的訪問。以下顯示了Resource接口定義的方法
public interface Resource extends InputStreamSource {boolean exists();default boolean isReadable() {return this.exists();}default boolean isOpen() {return false;}default boolean isFile() {return false;}URL getURL() throws IOException;URI getURI() throws IOException;File getFile() throws IOException;default ReadableByteChannel readableChannel() throws IOException {return Channels.newChannel(this.getInputStream());}long contentLength() throws IOException;long lastModified() throws IOException;Resource createRelative(String relativePath) throws IOException;@NullableString getFilename();String getDescription();
}
Resource接口繼承了InputStreamSource接口,提供了很多InputStreamSource所沒有的方法。InputStreamSource接口,只有一個方法:
public interface InputStreamSource {InputStream getInputStream() throws IOException;}
其中一些重要的方法:
getInputStream(): 找到并打開資源,返回一個InputStream以從資源中讀取。預計每次調用都會返回一個新的InputStream(),調用者有責任關閉每個流
exists(): 返回一個布爾值,表明某個資源是否以物理形式存在
isOpen: 返回一個布爾值,指示此資源是否具有開放流的句柄。如果為true,InputStream就不能夠多次讀取,只能夠讀取一次并且及時關閉以避免內存泄漏。對于所有常規資源實現,返回false,但是InputStreamResource除外。
getDescription(): 返回資源的描述,用來輸出錯誤的日志。這通常是完全限定的文件名或資源的實際URL。
其他方法:
isReadable(): 表明資源的目錄讀取是否通過getInputStream()進行讀取。
isFile(): 表明這個資源是否代表了一個文件系統的文件。
getURL(): 返回一個URL句柄,如果資源不能夠被解析為URL,將拋出IOException
getURI(): 返回一個資源的URI句柄
getFile(): 返回某個文件,如果資源不能夠被解析稱為絕對路徑,將會拋出FileNotFoundException
lastModified(): 資源最后一次修改的時間戳
createRelative(): 創建此資源的相關資源
getFilename(): 資源的文件名是什么 例如:最后一部分的文件名 myfile.txt
8.3、Resource的實現類
Resource 接口是 Spring 資源訪問策略的抽象,它本身并不提供任何資源訪問實現,具體的資源訪問由該接口的實現類完成——每個實現類代表一種資源訪問策略。Resource一般包括這些實現類:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource
8.3.1、UrlResource訪問網絡資源
Resource的一個實現類,用來訪問網絡資源,它支持URL的絕對路徑。
http:------該前綴用于訪問基于HTTP協議的網絡資源。
ftp:------該前綴用于訪問基于FTP協議的網絡資源
file: ------該前綴用于從文件系統中讀取資源
1)訪問基于HTTP協議的網絡資源
public class UrlResourceDemo {public static void main(String[] args) {//http前綴loadUrlResource("http://www.baidu.com");}//訪問前綴http、filepublic static void loadUrlResource(String path) {try {//創建Resource實現類的對象 UrlResourceUrlResource url = new UrlResource(path);System.out.println(url.exists());System.out.println(url.isReadable());System.out.println(url.isFile());System.out.println(url.getURL());System.out.println(url.getURI());System.out.println(url.getFilename());byte[] bytes = new byte[100];int read = url.getInputStream().read(bytes);System.out.println(new String(bytes));} catch (Exception e) {throw new RuntimeException(e);}}
}
2)在項目根路徑下創建文件,從文件系統中讀取資源
public class UrlResourceDemo {public static void main(String[] args) {//file前綴loadUrlResource("file:atguigu.txt");}//訪問前綴http、filepublic static void loadUrlResource(String path) {try {//創建Resource實現類的對象 UrlResourceUrlResource url = new UrlResource(path);System.out.println(url.exists());System.out.println(url.isReadable());System.out.println(url.isFile());System.out.println(url.getURL());System.out.println(url.getURI());System.out.println(url.getFilename());byte[] bytes = new byte[100];int read = url.getInputStream().read(bytes);System.out.println(new String(bytes));} catch (Exception e) {throw new RuntimeException(e);}}
}
8.3.2 ClassPathResource 訪問類路徑下資源
ClassPathResource 用來訪問類加載路徑下的資源,相對于其他的 Resource 實現類,其主要優勢是方便訪問類加載路徑里的資源,尤其對于 Web 應用,ClassPathResource 可自動搜索位于 classes 下的資源文件,無須使用絕對路徑訪問。
1)實驗:在類路徑下創建文件atguigu.txt,使用ClassPathResource 訪問
//訪問類路徑下資源
public class ClassPathResourceDemo {public static void loadClasspathResource(String path) {//創建對象ClassPathResourceClassPathResource resource = new ClassPathResource(path);System.out.println(resource.getFilename());System.out.println(resource.getDescription());//獲取文件內容try {InputStream in = resource.getInputStream();byte[] b = new byte[1024];while(in.read(b)!=-1) {System.out.println(new String(b));}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) {loadClasspathResource("atguigu.txt");}
}
8.3.3、FileSystemResource 訪問文件系統資源
Spring 提供的 FileSystemResource 類用于訪問文件系統資源,使用 FileSystemResource 來訪問文件系統資源并沒有太大的優勢,因為 Java 提供的 File 類也可用于訪問文件系統資源。
8.3.4、ServletContextResource
8.3.5、InputStreamResource
8.3.6、ByteArrayResource
8.4、Resource類圖
8.5、ResourceLoader 接口
在ResourceLoader接口里有如下方法:
(1)Resource getResource(String location) : 該接口僅有這個方法,用于返回一個Resource實例。ApplicationContext實現類都實現ResourceLoader接口,因此ApplicationContext可直接獲取Resource實例。
8.5.1、使用演示
實驗一:ClassPathXmlApplicationContext獲取Resource實例
package com.atguigu.spring6.resouceloader;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;public class Demo1 {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext();
// 通過ApplicationContext訪問資源
// ApplicationContext實例獲取Resource實例時,
// 默認采用與ApplicationContext相同的資源訪問策略Resource res = ctx.getResource("atguigu.txt");System.out.println(res.getFilename());}
}
實驗二:FileSystemApplicationContext獲取Resource實例
package com.atguigu.spring6.resouceloader;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.Resource;public class Demo2 {public static void main(String[] args) {ApplicationContext ctx = new FileSystemXmlApplicationContext();Resource res = ctx.getResource("atguigu.txt");System.out.println(res.getFilename());}
}
8.5.3、ResourceLoader 總結
當Spring應用需要進行資源訪問時,實際上并不需要直接使用Resource實現類,而是調用ResourceLoader實例的getResource()方法來獲得資源,ReosurceLoader將會負責選擇Reosurce實現類,也就是確定具體的資源訪問策略,從而將應用程序和具體的資源訪問策略分離開來
8.6、ResourceLoaderAware 接口
ResourceLoaderAware接口實現類的實例將獲得一個ResourceLoader的引用,ResourceLoaderAware接口也提供了一個setResourceLoader()方法,該方法將由Spring容器負責調用,Spring容器會將一個ResourceLoader對象作為該方法的參數傳入。
==具體看 Spring Bean生命周期 --> 初始化Bean 中的 —> invokeAware ==
如果把實現ResourceLoaderAware接口的Bean類部署在Spring容器中,Spring容器會將自身當成ResourceLoader作為setResourceLoader()方法的參數傳入。由于ApplicationContext的實現類都實現了ResourceLoader接口,Spring容器自身完全可作為ResorceLoader使用
實驗:演示ResourceLoaderAware使用
第一步 創建類,實現ResourceLoaderAware接口
package com.atguigu.spring6.resouceloader;import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.ResourceLoader;public class TestBean implements ResourceLoaderAware {private ResourceLoader resourceLoader;//實現ResourceLoaderAware接口必須實現的方法//如果把該Bean部署在Spring容器中,該方法將會有Spring容器負責調用。//SPring容器調用該方法時,Spring會將自身作為參數傳給該方法。public void setResourceLoader(ResourceLoader resourceLoader) {this.resourceLoader = resourceLoader;}//返回ResourceLoader對象的應用public ResourceLoader getResourceLoader(){return this.resourceLoader;}}
第二步 創建bean.xml文件,配置TestBean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="testBean" class="com.atguigu.spring6.resouceloader.TestBean"></bean>
</beans>
第三步 測試
package com.atguigu.spring6.resouceloader;import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;public class Demo3 {public static void main(String[] args) {//Spring容器會將一個ResourceLoader對象作為該方法的參數傳入ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");TestBean testBean = ctx.getBean("testBean",TestBean.class);//獲取ResourceLoader對象ResourceLoader resourceLoader = testBean.getResourceLoader();System.out.println("Spring容器將自身注入到ResourceLoaderAware Bean 中 ? :" + (resourceLoader == ctx));//加載其他資源Resource resource = resourceLoader.getResource("atguigu.txt");System.out.println(resource.getFilename());System.out.println(resource.getDescription());}
}
8.7 應用程序上下文和資源路徑
不管以怎樣的方式創建ApplicationContext實例,都需要為ApplicationContext指定配置文件,Spring允許使用一份或多分XML配置文件。當程序創建ApplicationContext實例時,通常也是以Resource的方式來訪問配置文件的,所以ApplicationContext完全支持ClassPathResource、FileSystemResource、ServletContextResource等資源訪問方式。
ApplicationContext確定資源訪問策略通常有兩種方法:
- (1)使用ApplicationContext實現類指定訪問策略。
- (2)使用前綴指定訪問策略。
8.8.1、ApplicationContext實現類指定訪問策略
創建ApplicationContext對象時,通常可以使用如下實現類:
(1) ClassPathXMLApplicationContext : 對應使用ClassPathResource進行資源訪問。
(2)FileSystemXmlApplicationContext : 對應使用FileSystemResource進行資源訪問。
(3)XmlWebApplicationContext : 對應使用ServletContextResource進行資源訪問。
當使用ApplicationContext的不同實現類時,就意味著Spring使用響應的資源訪問策略。