目錄
1 Resource簡介
2 通過ResourceLoader獲取資源
3 在bean中獲取Resource的方式
1 Resource簡介
在spring內部,針對於資源文件有一個統一的接口Resource表示。其主要實現類有ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、ServletContextResource和InputStreamResource。Resource接口中主要定義有以下方法:
l exists():用於判斷對應的資源是否真的存在。
l isReadable():用於判斷對應資源的內容是否可讀。需要注意的是當其結果爲true的時候,其內容未必真的可讀,但如果返回false,則其內容必定不可讀。
l isOpen():用於判斷當前資源是否代表一個已打開的輸入流,如果結果爲true,則表示當前資源的輸入流不可多次讀取,而且在讀取以後需要對它進行關閉,以防止內存泄露。該方法主要針對於InputStreamResource,實現類中只有它的返回結果爲true,其他都爲false。
l getURL():返回當前資源對應的URL。如果當前資源不能解析爲一個URL則會拋出異常。如ByteArrayResource就不能解析爲一個URL。
l getFile():返回當前資源對應的File。如果當前資源不能以絕對路徑解析爲一個File則會拋出異常。如ByteArrayResource就不能解析爲一個File。
l getInputStream():獲取當前資源代表的輸入流。除了InputStreamResource以外,其它Resource實現類每次調用getInputStream()方法都將返回一個全新的InputStream。
ClassPathResource可用來獲取類路徑下的資源文件。假設我們有一個資源文件test.txt在類路徑下,我們就可以通過給定對應資源文件在類路徑下的路徑path來獲取它,new ClassPathResource(“test.txt”)。
FileSystemResource可用來獲取文件系統裏面的資源。我們可以通過對應資源文件的文件路徑來構建一個FileSystemResource。FileSystemResource還可以往對應的資源文件裏面寫內容,當然前提是當前資源文件是可寫的,這可以通過其isWritable()方法來判斷。FileSystemResource對外開放了對應資源文件的輸出流,可以通過getOutputStream()方法獲取到。
UrlResource可用來代表URL對應的資源,它對URL做了一個簡單的封裝。通過給定一個URL地址,我們就能構建一個UrlResource。
ByteArrayResource是針對於字節數組封裝的資源,它的構建需要一個字節數組。
ServletContextResource是針對於ServletContext封裝的資源,用於訪問ServletContext環境下的資源。ServletContextResource持有一個ServletContext的引用,其底層是通過ServletContext的getResource()方法和getResourceAsStream()方法來獲取資源的。
InputStreamResource是針對於輸入流封裝的資源,它的構建需要一個輸入流。
- public class ResourceTest {
- /**
- * ClassPathResource可以用來獲取類路徑下的資源
- * @throws IOException
- */
- @Test
- public void testClassPath() throws IOException {
- Resource resource = new ClassPathResource("test.txt");
- String fileName = resource.getFilename();
- System.out.println(fileName);
- // resource.getFile(); //獲取資源對應的文件
- // resource.getURL(); //獲取資源對應的URL
- if (resource.isReadable()) {
- //每次都會打開一個新的流
- InputStream is = resource.getInputStream();
- this.printContent(is);
- }
- }
- /**
- * FileSystemResource可以用來獲取文件系統裏面的資源,對於FileSystemResource而言我們
- * 可以獲取到其對應的輸出流。
- * @throws IOException
- */
- @Test
- public void testFileSystem() throws IOException {
- FileSystemResource resource = new FileSystemResource("D:\\test.txt");
- if (resource.isReadable()) {
- //FileInputStream
- printContent(resource.getInputStream());
- }
- if (resource.isWritable()) {
- //每次都會獲取到一個新的輸出流
- OutputStream os = resource.getOutputStream();
- BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
- bw.write("你好,中國!");
- bw.flush();
- if (os != null) {
- os.close();
- }
- if (bw != null) {
- bw.close();
- }
- }
- }
- /**
- * 針對於URL進行封裝的Resource,可用來從URL獲取資源內容
- * @throws Exception
- */
- @Test
- public void testURL() throws Exception {
- UrlResource resource = new UrlResource("http://www.google.com.hk");
- if (resource.isReadable()) {
- //URLConnection對應的getInputStream()。
- printContent(resource.getInputStream());
- }
- }
- /**
- * 針對於字節數組封裝的Resource,用來從字節數組獲取資源內容
- * @throws IOException
- */
- @Test
- public void testByteArray() throws IOException {
- ByteArrayResource resource = new ByteArrayResource("Hello".getBytes());
- //ByteArrayInputStream()
- printContent(resource.getInputStream());
- }
- /**
- * 針對於輸入流的Resource,其getInputStream()方法只能被調用一次。
- * @throws Exception
- */
- @Test
- public void testInputStream() throws Exception {
- InputStream is = new FileInputStream("D:\\test.txt");
- InputStreamResource resource = new InputStreamResource(is);
- //對於InputStreamResource而言,其getInputStream()方法只能調用一次,繼續調用將拋出異常。
- InputStream target = resource.getInputStream(); //返回的就是構件時的那個InputStream
- //is將在printContent方法裏面進行關閉
- printContent(target);
- }
- /**
- * 輸出輸入流的內容
- * @param is
- * @throws IOException
- */
- private void printContent(InputStream is) throws IOException {
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- String line;
- while ((line=br.readLine()) != null) {
- System.out.println(line);
- }
- if (is != null) {
- is.close();
- }
- if (br != null) {
- br.close();
- }
- }
- }
2 通過ResourceLoader獲取資源
在Spring裏面還定義有一個ResourceLoader接口,該接口中只定義了一個用於獲取Resource的getResource(String location)方法。它的實現類有很多,這裏我們先挑一個DefaultResourceLoader來講。DefaultResourceLoader在獲取Resource時採用的是這樣的策略:首先判斷指定的location是否含有“classpath:”前綴,如果有則把location去掉“classpath:”前綴返回對應的ClassPathResource;否則就把它當做一個URL來處理,封裝成一個UrlResource進行返回;如果當成URL處理也失敗的話就把location對應的資源當成是一個ClassPathResource進行返回。
- @Test
- public void testResourceLoader() {
- ResourceLoader loader = new DefaultResourceLoader();
- Resource resource = loader.getResource("http://www.google.com.hk");
- System.out.println(resource instanceof UrlResource); //true
- //注意這裏前綴不能使用“classpath*:”,這樣不能真正訪問到對應的資源,exists()返回false
- resource = loader.getResource("classpath:test.txt");
- System.out.println(resource instanceof ClassPathResource); //true
- resource = loader.getResource("test.txt");
- System.out.println(resource instanceof ClassPathResource); //true
- }
ApplicationContext接口也繼承了ResourceLoader接口,所以它的所有實現類都實現了ResourceLoader接口,都可以用來獲取Resource。
對於ClassPathXmlApplicationContext而言,它在獲取Resource時繼承的是它的父類DefaultResourceLoader的策略。
FileSystemXmlApplicationContext也繼承了DefaultResourceLoader,但是它重寫了DefaultResourceLoader的getResourceByPath(String path)方法。所以它在獲取資源文件時首先也是判斷指定的location是否包含“classpath:”前綴,如果包含,則把location中“classpath:”前綴後的資源從類路徑下獲取出來,當做一個ClassPathResource;否則,繼續嘗試把location封裝成一個URL,返回對應的UrlResource;如果還是失敗,則把location指定位置的資源當做一個FileSystemResource進行返回。
3 在bean中獲取Resource的方式
通過上面內容的介紹,我們知道,在bean中獲取Resource主要有以下幾種方式:
1.直接通過new各種類型的Resource來獲取對應的Resource。
2.在bean裏面獲取到對應的ApplicationContext,再通過ApplicationContext的getResource(String path)方法獲取對應的Resource。
3.直接創建DefaultResourceLoader的實例,再調用其getResource(String location)方法獲取對應的Resource。
4.通過依賴注入的方式把Resource注入到bean中。示例如下:
類ClassA:
- public class ClassA {
- //持有一個Resource屬性
- private Resource resource;
- public void printContent() {
- if (resource != null && resource.exists()) {
- if (resource.isReadable()) {
- InputStream is;
- try {
- is = resource.getInputStream();
- BufferedReader br = new BufferedReader(new InputStreamReader(is));
- String line;
- while ((line=br.readLine()) != null) {
- System.out.println(line);
- }
- if (is != null) {
- is.close();
- }
- if (br != null) {
- br.close();
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- public void setResource(Resource resource) {
- this.resource = resource;
- }
- }
applicationContext.xml文件:
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.0.xsd">
- <bean id="classA" class="com.xxx.ClassA">
- <property name="resource">
- <value>classpath:applicationContext.xml</value>
- </property>
- </bean>
- </beans>
從上面可以看到我們有一個類ClassA,其持有一個Resource屬性,在Spring bean配置文件中我們直接給ClassA注入了屬性resource。其對應的測試代碼如下: