在Spring内部實作機制,針對于資源檔案(配置的xml檔案)有一個統一的接口Resource。
1.exists():判斷資源檔案是否存在。
2.isReadable():用于判斷對應資源的内容是否可讀。傳回false肯定不可讀,true也不一定可讀。
3.isOpen():用于判斷目前資源是否代表一個已打開的輸入流,如果結果為true,則表示目前資源的輸入流不可多次讀取,而且在讀取以後需要對它進行關閉,以防止記憶體洩露。該方法主要針對于InputStreamResource,實作類中隻有它的傳回結果為true,其他都為false。
4.getURL():傳回目前資源對應的URL。如果目前資源不能解析為一個URL則會抛出異常。如ByteArrayResource就不能解析為一個URL。
5.getFile():傳回目前資源對應的File。如果目前資源不能以絕對路徑解析為一個File則會抛出異常。如ByteArrayResource就不能解析為一個File。
6.getInputStream():擷取目前資源代表的輸入流。除了InputStreamResource以外,其它Resource實作類每次調用getInputStream()方法都将傳回一個全新的InputStream。
主要常用的有如下:
ClassPathResource、FileSystemResource、UrlResource、ByteArrayResource、ServletContextResource和InputStreamResource。
主要應用于類路徑下的資源檔案使用classLoader類加載器進行讀取使用
使用
ClassPathResource resource = new ClassPathResource("springok/bean/beanFactory.xml");
System.out.println(resource.getFilename());
源碼如下:
public ClassPathResource(String path, ClassLoader classLoader) {
Assert.notNull(path, "Path must not be null");
String pathToUse = StringUtils.cleanPath(path);
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
this.path = pathToUse;
this.classLoader = (classLoader != null ? classLoader : ClassUtils.getDefaultClassLoader());
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {
is = this.clazz.getResourceAsStream(this.path);
else if (this.classLoader != null) {
is = this.classLoader.getResourceAsStream(this.path);
else {
is = ClassLoader.getSystemResourceAsStream(this.path);
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
return is;
可用來擷取檔案系統裡面的資源。
private final File file;
private final String path;
/**
* Create a new {@code FileSystemResource} from a {@link File} handle.
* <p>Note: When building relative resources via {@link #createRelative},
* the relative path will apply <i>at the same directory level</i>:
* e.g. new File("C:/dir1"), relative path "dir2" -> "C:/dir2"!
* If you prefer to have relative paths built underneath the given root
* directory, use the {@link #FileSystemResource(String) constructor with a file path}
* to append a trailing slash to the root path: "C:/dir1/", which
* indicates this directory as root for all relative paths.
* @param file a File handle
*/
public FileSystemResource(File file) {
Assert.notNull(file, "File must not be null");
this.file = file;
this.path = StringUtils.cleanPath(file.getPath());
代表URL對應的資源。
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;
針對于位元組數組封裝的資源,它的建構需要一個位元組數組
private final byte[] byteArray;
private final String description;
* Create a new ByteArrayResource.
* @param byteArray the byte array to wrap
public ByteArrayResource(byte[] byteArray) {
this(byteArray, "resource loaded from byte array");
針對于ServletContext封裝的資源,用于通路ServletContext環境下的資源。具體還是調用ServletContext 方法。
private final ServletContext servletContext;
public ServletContextResource(ServletContext servletContext, String path) {
// check ServletContext
Assert.notNull(servletContext, "Cannot resolve ServletContextResource without ServletContext");
this.servletContext = servletContext;
Assert.notNull(path, "Path is required");
if (!pathToUse.startsWith("/")) {
pathToUse = "/" + pathToUse;
輸入流封裝的資源,它的建構需要一個輸入流。
private final InputStream inputStream;
private boolean read = false;
public InputStreamResource(InputStream inputStream) {
this(inputStream, "resource loaded through InputStream");
在Spring裡面還定義有一個ResourceLoader接口,該接口中隻定義了一個用于擷取Resource的getResource(String location)方法。它的實作類有很多,這裡我們先挑一個DefaultResourceLoader來講。DefaultResourceLoader在擷取Resource時采用的是這樣的政策:首先判斷指定的location是否含有“classpath:”字首,如果有則把location去掉“classpath:”字首傳回對應的ClassPathResource;否則就把它當做一個URL來處理,封裝成一個UrlResource進行傳回;如果當成URL處理也失敗的話就把location對應的資源當成是一個ClassPathResource進行傳回。
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//classpath:
if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
// Try to parse the location as a URL...
URL url = new URL(location);
return new UrlResource(url);
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
測試:
@Test
public void testResourceLoader() {
ResourceLoader loader = new DefaultResourceLoader();
Resource resource = loader.getResource("http://www.springok.com.");
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");
ApplicationContext接口也繼承了ResourceLoader接口,是以它的所有實作類都實作了ResourceLoader接口,都可以用來擷取Resource。
對于ClassPathXmlApplicationContext而言,它在擷取Resource時繼承的是它的父類DefaultResourceLoader的政策。
FileSystemXmlApplicationContext也繼承了DefaultResourceLoader,但是它重寫了DefaultResourceLoader的getResourceByPath(String path)方法。是以它在擷取資源檔案時首先也是判斷指定的location是否包含“classpath:”字首,如果包含,則把location中“classpath:”字首後的資源從類路徑下擷取出來,當做一個ClassPathResource;否則,繼續嘗試把location封裝成一個URL,傳回對應的UrlResource;如果還是失敗,則把location指定位置的資源當做一個FileSystemResource進行傳回。
通過上面内容的介紹,我們知道,在bean中擷取Resource主要有以下幾種方式:
1.直接通過new各種類型的Resource來擷取對應的Resource。
2.在bean裡面擷取到對應的ApplicationContext,再通過ApplicationContext的getResource(String path)方法擷取對應的Resource。
3.直接建立DefaultResourceLoader的執行個體,再調用其getResource(String location)方法擷取對應的Resource。
4.通過依賴注入的方式把Resource注入到bean中。示例如下:
使用比較簡單如下:
public class ClassA {
//持有一個Resource屬性
private Resource resource;
配置檔案如下:
<bean id="" class="">
<property name="resource">
<value>classpath:applicationContext.xml</value>
</property>
</bean>