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;
}
相关文章
相关标签/搜索