Spring Resource源码分析
- 基本信息
Spring为了方便程序调用不同类型的资源而定义的接口。Spring提供若干实现,方便我们针对不同的资源获取资源文件以及对具体内容的操作。常用的有以下三种:
- 通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
- 通过 ClassPathResource 以类路径的方式进行访问;
- 通过 ServletContextResource 以相对于Web应用根目录的方式进行访问。
如下图为基本的类关系图,我们可以看到Resource的主要继承接口,以及对应的三大主类的实现。

- 接口代码以及逻辑关系
1, InputStreamSource
该接口提供最为资源读取流的简单接口。只有一个方法:
-
InputStream getInputStream()throwsIOException;
该方法每次调用都会返回一个新的流对象。
2, Resource接口。定义了一组对底层资源操作的基本方法。
-
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,并提供自身的两个写入方法:
-
boolean isWritable(); OutputStream getOutputStream()throwsIOException;
4, ContextResource:通过上下文获取Resource,例如:javax.servlet.ServletContext。
该接口新增一个方法。
-
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; }
欢迎转载,但转载请注明原文链接[博客园: http://www.cnblogs.com/jingLongJun/]
[CSDN博客:http://blog.csdn.net/mergades]。
如相关博文涉及到版权问题,请联系本人。
[CSDN博客:http://blog.csdn.net/mergades]。
如相关博文涉及到版权问题,请联系本人。

浙公网安备 33010602011771号