Spring Resource源碼分析

  • 基本信息   
 Spring爲了方便程序調用不一樣類型的資源而定義的接口。Spring提供若干實現,方便咱們針對不一樣的資源獲取資源文件以及對具體內容的操做。經常使用的有如下三種:
  1. 經過 FileSystemResource 以文件系統絕對路徑的方式進行訪問;
  2. 經過 ClassPathResource 以類路徑的方式進行訪問;
  3. 經過 ServletContextResource 以相對於Web應用根目錄的方式進行訪問。
以下圖爲基本的類關係圖,咱們能夠看到Resource的主要繼承接口,以及對應的三大主類的實現。
 
  • 接口代碼以及邏輯關係
    1,  InputStreamSource
該接口提供最爲資源讀取流的簡單接口。只有一個方法:
    1. InputStream getInputStream()throwsIOException;

       

該方法每次調用都會返回一個新的流對象。
   2,  Resource接口。定義了一組對底層資源操做的基本方法。
  1. boolean exists();
    boolean isReadable();
    boolean isOpen();
    URL getURL()throwsIOException;
    URI getURI()throwsIOException;
    File getFile()throwsIOException;
    long contentLength()throwsIOException;
    long lastModified()throwsIOException;
    Resource createRelative(String relativePath)throwsIOException;
    String getFilename();
    String getDescription();

     

   3, WritableResource:該接口提供可供寫入的資源。該接口繼承自Resource,並提供自身的兩個寫入方法:
  1. boolean isWritable();
    OutputStream getOutputStream()throwsIOException;

     

  4, ContextResource:經過上下文獲取Resource,例如: javax.servlet.ServletContext。
  該接口新增一個方法。
  1. String getPathWithinContext();

     

    5,AbstractResource:基礎抽象類,對Resource接口的部分方法實現一個簡單的實現。
    該類的源碼能夠大概看下就能夠了,基本屬於一些簡單的實現。
 
  • ClassPathResource
    1,ClassPathResource用來訪問類加載路徑下的資源,相對於其餘Resource實現類,主要優點是 方便訪問類加載路徑中的資源,尤爲針對Web應用。ClassPathResource能夠自動搜索位於WEB-INF/classes下的資源文件,無須使用絕對路徑訪問。好比,以下代碼:
 
import java.util.List;
 
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.core.io.ClassPathResource;
 
public class ResourceTest {
 
public static void main(String[] args) throws Exception {
 
//applicationContext.xml,位於\WEB-INF\classes\spring\下
ClassPathResource cpr = new ClassPathResource("/spring/applicationContext.xml");
System.out.println(cpr.getFilename());
 
//SAX解析
SAXReader reader = new SAXReader();
Document doc = reader.read(cpr.getFile());
Element root = doc.getRootElement();
@SuppressWarnings("unchecked")
List<Element> l = root.elements();
for(Element e : l){
 
System.out.println(e.asXML());
}
}
}

 

    2,成員變量:
    
private final String path;
 
private ClassLoader classLoader;
 
private Class<?> clazz;

 

    -1,path:指定了當前文件的絕對路徑。對應構造方法:
    
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}

 

    -2,classLoader:類加載器。
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());
}

 

同時,在構造ClasspathResource時,咱們也能夠指定類加載器。
    
ClassPathResource cpr = new ClassPathResource("/spring/applicationContext.xml", ResourceTest.class.getClassLoader());

 

    -3,clazz: 類對象,經過類對象,能夠在使用中獲取一些信息,好比:
public final ClassLoader getClassLoader() {
return (this.clazz != null ? this.clazz.getClassLoader() : this.classLoader);
}

 

3,方法:
    -1,getInputStream:獲取一個InputStream對象
@Override
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {//clazz對象是否爲空,不爲空經過clazz獲取輸入流
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;
}

 

    -2,getDescription:獲取對應的資源描述
public String getDescription() {
StringBuilder builder = new StringBuilder("class path resource [");
String pathToUse = path;
if (this.clazz != null && !pathToUse.startsWith("/")) {
builder.append(ClassUtils.classPackageAsResourcePath(this.clazz));
builder.append('/');
}
if (pathToUse.startsWith("/")) {
pathToUse = pathToUse.substring(1);
}
builder.append(pathToUse);
builder.append(']');
return builder.toString();
}

 

    -3,getFile():獲取File對象。父類AbstractFileResolvingResource類提供。
@Override
public File getFile() throws IOException {
URL url = getURL();//獲取URL
if (url.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
return VfsResourceDelegate.getResource(url).getFile();
}
return ResourceUtils.getFile(url, getDescription());
}

 

    類自身重寫getURL方法:
public URL getURL() throws IOException {
URL url = resolveURL();//獲取URL
if (url == null) {
throw new FileNotFoundException(getDescription() + " cannot be resolved to URL because it does not exist");
}
return url;
}

 

自身調用,resolveURL(),獲取URL方法,經過不一樣的參數,獲取對應的URL。
protected URL resolveURL() {
if (this.clazz != null) {
return this.clazz.getResource(this.path);
}
else if (this.classLoader != null) {
return this.classLoader.getResource(this.path);
}
else {
return ClassLoader.getSystemResource(this.path);
}
}
  • FileSystemResourcce
 1,FileSystemResource用於訪問文件系統資源,使用FileSystemResource訪問文件系統資源優點不是太大,由於File類也能夠實現此方法。以下代碼:
public static void main(String[] args) {
 
//applicationContext.xml放置於src目錄下
//直接訪問文件
FileSystemResource fsr = new FileSystemResource("/spring/applicationContext.xml");
System.out.println(fsr.getFile().exists());//false
 
fsr = new FileSystemResource("src/applicationContext.xml");
System.out.println(fsr.getFile().exists());//true
 
}

 

    2,成員變量:
    
private final File file;
 
private final String path;

 

    -1,file:文件對象。
    
public FileSystemResource(File file) {
Assert.notNull(file, "File must not be null");
this.file = file;
this.path = StringUtils.cleanPath(file.getPath());
}
    -2,path:對應加載文件的路勁。
public FileSystemResource(String path) {
Assert.notNull(path, "Path must not be null");
this.file = new File(path);
this.path = StringUtils.cleanPath(path);
}

 

因而可知,FileSystemResource內部,仍是使用的
this.file = new File(path);

 

形式獲取到對應的文件對象。
3,方法:
    -1,getURL():經過file對象獲取到對應的URL。
@Override
public URL getURL() throws IOException {
return this.file.toURI().toURL();
}

 

-2,getFile():返回file對象。
@Override
public File getFile() {
return this.file;
}
相關文章
相關標籤/搜索