Resource
?當咱們學習Spring時,咱們總會在xml中對bean進行聲明,而後再經過下面的代碼片斷來獲取bean。代碼以下:java
import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Context { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring.xml");//一、加載配置文件 System.err.println(ctx.getBean("stu").toString());//二、經過配置文件獲取一個bean並打印 } }
上面第一行代碼加載了一個資源文件Spring.xml
,這個資源文件在Spring中屬於Resource
的一種。這樣講,Spring把各類類型的文件,二進制流都稱之爲Resource
,只不過對於Spring開發者來講,Resource
大多都是xml文件。web
Resource是一個接口,接口裏邊定義了很是多關於文件的操做策略
,好比spring
exists():判斷資源是否存在
getURL():獲取資源的URL
getFilename():獲取資源的名稱
......(方法很是多,我就不一一列舉了)
Resource
接口是具體資源訪問策略的抽象,也是全部資源訪問類所實現的接口。Resource
接口自己沒有提供訪問任何底層資源的實現邏輯,針對不一樣的底層資源,Spring 將會提供不一樣的 Resource
實現類,不一樣的實現類負責不一樣的資源訪問邏輯。數據庫
很是重要的一點,這也是Spring Resource設計最美妙的地方,那就是Spring 在Resource資源處理上採用啦策略模式
,這也是我爲何上面把Resource接口中的方法稱之爲策略
的緣由了!api
若是還不瞭解Java 策略模式
的朋友請先自行學習!數組
Spring Resource
接口類結構圖爲了更好地理解,在這裏我先放一張策略模式
的UML圖,它的具體內容本文不講。函數
好了!圖片放上去了,那麼策略模式
在Resource
體系上如何體現出來呢?學習
Resource
接口至關於咱們的策略
AbstractResource
在內都屬於咱們的具體策略實現
context
角色到哪裏去了呢?哈哈,作生意不能忘了咱們的老本啊!它就是咱們的IOC容器ApplicationContext
,它是咱們策略模式中最最最具備決策能力的老大了至於爲何容器就能夠處理咱們的Resource
,我接下去會說到!spa
很明顯,Resource
是資源的最高抽象,一般咱們的應用程序不是都從classpath
下去加載咱們的xml文件,咱們也能夠經過一個URL
,URI
,InputStream
等方式獲取一個資源,這就是Spring把資源的獲取方式和資源的定義之間解耦了!.net
ResourceLoader
接口ResourceLoader
:該接口實現類的實例能夠得到一個 Resource 實例。。在 ResourceLoader
接口裏有以下方法:
Resource getResource(String location)
:該接口僅包含這個方法,該方法用於返回一個 Resource
實例。ApplicationContext
的實現類都實現 ResourceLoader
接口,而該接口又返回一個Resource
實例,所以 ApplicationContext
可用於直接獲取 Resource
實例,這也是爲何容器就能夠處理Resource
的緣由!
UrlResource 封裝了一個 java.net.URL 對象,用來訪問 URL 能夠正常訪問的任意對象,好比文件、an HTTP target, an FTP target, 等等。全部的 URL 均可以用一個標準化的字符串來表示。如經過正確的標準化前綴,能夠用來表示當前 URL 的類型,當中就包括用於訪問文件系統路徑的 file:,經過 http 協議訪問資源的 http:,經過 ftp 協議訪問資源的 ftp:,還有不少……
能夠顯式化地使用 UrlResource 構造函數來建立一個 UrlResource,不過一般咱們能夠在調用一個 api 方法是,使用一個表明路徑的 String 參數來隱式建立一個 UrlResource。對於後一種狀況,會由一個 javabean PropertyEditor 來決定建立哪種 Resource。若是路徑裏包含某一個通用的前綴(如 classpath:),PropertyEditor 會根據這個通用的前綴來建立恰當的 Resource;反之,若是 PropertyEditor 沒法識別這個前綴,會把這個路徑做爲一個標準的 URL 來建立一個 UrlResource。
可使用 ClassPathResource 來獲取類路徑上的資源。ClassPathResource 可使用線程上下文的加載器、調用者提供的加載器或指定的類中的任意一個來加載資源。
ClassPathResource 能夠從類路徑上加載資源,其可使用線程上下文加載器、指定加載器或指定的 class 類型中的任意一個來加載資源。
當類路徑上資源存於文件系統中,ClassPathResource 支持以 java.io.File 的形式訪問,可當類路徑上的資源存於還沒有解壓(沒有 被Servlet 引擎或其餘可解壓的環境解壓)的 jar 包中,ClassPathResource 就再也不支持以 java.io.File 的形式訪問。鑑於上面所說這個問題,spring 中各式 Resource 實現都支持以 jave.net.URL 的形式訪問。
能夠顯式使用 ClassPathResource 構造函數來建立一個 ClassPathResource ,不過一般咱們能夠在調用一個 api 方法時,使用一個表明路徑的 String 參數來隱式建立一個 ClassPathResource。對於後一種狀況,會由一個 javabean PropertyEditor 來識別路徑中 classpath: 前綴,從而建立一個 ClassPathResource。
這是針對 java.io.File 提供的 Resource 實現。顯然,咱們可使用 FileSystemResource 的 getFile() 函數獲取 File 對象,使用 getURL() 獲取 URL 對象。
這是爲了獲取 web 根路徑的 ServletContext 資源而提供的 Resource 實現。
ServletContextResource 徹底支持以流和 URL 的方式訪問,可只有當 web 項目是已解壓的(不是以 war 等壓縮包形式存在)且該 ServletContext 資源存於文件系統裏,ServletContextResource 才支持以 java.io.File 的方式訪問。至於說到,咱們的 web 項目是否已解壓和相關的 ServletContext 資源是否會存於文件系統裏,這個取決於咱們所使用的 Servlet 容器。若 Servlet 容器沒有解壓 web 項目,咱們能夠直接以 JAR 的形式的訪問,或者其餘能夠想到的方式(如訪問數據庫)等。
這是針對 InputStream 提供的 Resource 實現。建議,在確實沒有找到其餘合適的 Resource 實現時,才使用 InputSteamResource。若是能夠,儘可能選擇 ByteArrayResource 或其餘基於文件的 Resource 實現來代替。
與其餘 Resource 實現已比較,InputStreamRsource 倒像一個已打開資源的描述符,所以,調用 isOpen() 方法會返回 true。除了在須要獲取資源的描述符或須要從輸入流屢次讀取時,都不要使用 InputStreamResource 來讀取資源。
這是針對字節數組提供的 Resource 實現。能夠經過一個字節數組來建立 ByteArrayResource。
當須要從字節數組加載內容時,ByteArrayResource 是一個不錯的選擇,使用 ByteArrayResource 能夠不用求助於 InputStreamResource。
策略模式
在Spring中使用有什麼優點當 Spring
應用須要進行資源訪問時,實際上並不須要直接使用 Resource
實現類,而是調用 ApplicationContext
實例的 getResource()
方法來得到資源,ApplicationContext
將會負責選擇 Resource
的實現類,也就是肯定具體的資源訪問策略,從而將應用程序和具體的資源訪問策略分離開來。
既然有那麼多的優點,下面就在來解釋咱們上面的第一段代碼,爲何要使用ClassPathXmlApplicationContext
這個類來對資源進行加載?
咱們都知道,在容器ApplicationContext
下有不少的實現,好比FileSystemXmlApplicationContext
,ClassPathXmlApplicationContext
,XmlWebApplicationContext
,並且咱們加載配置文件的方式一般也是使用它們來進行加載,在Spring中,ApplicationContext
的實現類顧名思義也是對應了咱們Resource
接口的一些實現策略,好比ClassPathResource
,FileSystemResource
等。