Spring ClassPathResource详解

        org.springframework.core.io.ClassPathResource位于Spring核心core下,用以表达类路径下的资源。
        首先简要说明一下什么是classpath,顾名思义,就是存放*.class类文件的路径,或者说ClassLoader加载类时为找到 *.class文件的路径。我们以一个WEB项目为例,发布后的目录结构大致如下:

Spring ClassPathResource详解_第1张图片

        然后以Tomcat为例,看一下WEB项目类加载时候的目录,参考 Tomcat Class Loader How-To 中的说明:

WebappX — A class loader is created for each web application that is deployed in a single Tomcat instance. All unpacked classes and resources in the /WEB-INF/classes directory of your web application, plus classes and resources in JAR files under the /WEB-INF/lib directory of your web application, are made visible to this web application, but not to other ones.

        因此,对于部署在Tomcat上的WEB应用来说,/WEB-INF/classes和/WEB-INF/lib目录就是我们所指的classpath。

        ClassPathResource是org.springframework.core.io.Resource接口的实现类。可以使用ClassLoader或Class类加载资源。支持转换为java.io.File对象(在Jar文件中的资源除外)。其继承实现关系图如下:

Spring ClassPathResource详解_第2张图片

        ClasspathResource类的属性变量和构造方法如下:

	private final String path;
	@Nullable
	private ClassLoader classLoader;// 通过ClassLoader加载资源文件
	@Nullable
	private Class<?> clazz; // 通过Class类加载资源文件
	
	// 通过类路径创建resource
	public ClassPathResource(String path){...}
	
	// 通过类路径和给定的ClassLoader创建resource
	public ClassPathResource(String path, @Nullable ClassLoader classLoader){...}
	
	// 通过类路径和给定的Class类创建resource
	public ClassPathResource(String path, @Nullable Class<?> clazz){...}
	
	// 通过类路径和给定的ClassLoader或Class创建resource
	protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz){...}

        在类继承关系中,每个类定义的方法如下:

Resource AbstractResource AbstractFileResolvingResource ClassPathResource
对底层资源的抽象描述
比如文件或类路径资源
对资源接口描述的基础实现
预先实现特定的行为
将URL解析为文件资源引用的抽象基类,尤其对JBOOS的vfs文件协议的支持 类路径资源的Resource实现
boolean exists()
判断该资源是否存在
public boolean exists()
实现父接口方法,检查资源(文件或目录)File对象或资源(文件)InputStream对象是否打开
public boolean exists()
重写父类方法,getURL后如果URL的文件协议是file:vfsfile:vfs则返回getFile().exists()直接判断该文件是否存在,如果非上述文件协议则尝试判断是否网络资源,通过HTTP请求看是否返回HTTP Status-Code=200,如果扔非上述,则尝试getInputStream().close()看文件流是否可打开
public boolean exists()
重写父类方法,判断是否能获取到该资源的URL对象
boolean isReadable()
是否可通过InputStreamSource.getInputStream()读取,这里注意返回true仍然可能读取失败,但返回false一定是不能读取
默认返回exists()
public boolean isReadable()
实现父接口方法,该方法在当资源存在的情况下始终返回true,返回值与父接口方法中定义的默认返回值一致,即返回exists()
public boolean isReadable()
重写父类方法,getURL后如果URL的文件协议是file:vfsfile:vfs则getFile得到该资源File对象,判断该File资源是否非目录且canRead可读,如果非上述文件协议则尝试调用网络资源,判断是否可成功调用且返回内容长度大于0,如果扔非上述,则尝试getInputStream().close()看文件流是否可打开
boolean isOpen()
表明该资源是否有打开的stream流,如果返回true则InputStream无法多次读取,且读完之后关闭流以防止内存泄露
默认返回false
public boolean isOpen()
实现父接口方法,与接口方法中定义的默认返回值一致,即始终返回false
boolean isFile()
判断该文件是否是系统文件中的文件,true值表示(但不保证)可以成功调用getFile()方法
默认返回false
public boolean isFile()
实现父接口方法,与接口方法中定义的默认返回值一致,即始终返回false
public boolean isFile()
重写父类方法,getURL后如果url为vfs开头协议(vfs/vfsfile)则交给VfsResourceDelegate类判断,如果url为file协议则返回true
protected boolean isFile(URI uri)
重载isFile方法,根据指定的URI判断该资源是否是一个文件引用,如果URI的scheme以vfs开头则交给VfsResourceDelegate类判断,否则判断如果URI的scheme等于file则返回true
URL getURL()
返回该资源对应的URL
public URL getURL()
实现父接口方法,这里假设资源不能解析为URL,直接返回了FileNotFoundException异常
public URL getURL()
重写父类方法,根据类路径参数获取该资源的URL对象
URI getURI()
返回该资源对应的URI
public URI getURI()
实现父接口方法,基于getURL返回的URL构建一个URI
File getFile()
返回该资源的File对象
public File getFile()
实现父接口方法,这里假设资源无法解析为文件绝对路径,直接返回了FileNotFoundException异常
public File getFile()
重写父类方法,父类直接返回FileNotFoundException异常,在这里通过getURL获取到URL对象(具体URL由其子类确定,比如ClasspathResource重写了getURL通过类加载器获取到了类路径资源的URL),如果url为vfs开头协议(vfs/vfsfile)则交给VfsResourceDelegate类获取File对象,否则通过得到url获取File对象
protected File getFile(URI uri)
重载getFile方法,根据指定的URI获取资源File对象,如果URI的scheme以vfs开头则交给VfsResourceDelegate类获取
ReadableByteChannel readableChannel()
默认返回Channels.newChannel(getInputStream())
public ReadableByteChannel readableChannel()
实现父接口方法,与父接口的默认返回值相同
public ReadableByteChannel readableChannel()
根据指定的URI调用FileChannel.open 返回一个ReadableByteChannel对象
long contentLength()
返回该资源内容的长度
public long contentLength()
根据getInputStream()返回的InputStream,读取并计算资源的内容长度
public long contentLength()
根据getURL获得URL对象,如果是文件(file/vfsfile/vfs)URL返回文件长度,否则尝试网络连接获取资源并返回长度
long lastModified()
返回该资源最后一次修改的时间戳
public long lastModified()
获取并返回该资源文件的时间戳
public long lastModified()
根据getURL获取URL对象,如果是文件(file/vfsfile/vfs)或归档文件(jar/war/zip/vfszip/wsjar)则获取文件的最后修改时间戳,否则获取网络连接并获取最后修改时间戳
Resource createRelative(String relativePath)
根据相对于该资源的相对路径,创建一个Resource资源,比如classpath资源目录conf下有A.xml和B.xml,Resource a = new ClassPathResource("conf/A.xml"); 那么在创建b资源的时候就可以以a为参照Resource b = a.createRelative("B.xml");
public Resource createRelative(String relativePath)
实现父接口方法,这里假设改相对资源未被创建,直接返回了FileNotFoundException异常
public Resource createRelative(String relativePath)
重写父类方法,根据参照资源的类路径得到relativePath参数的真实classpath路径,并创建Resource资源对象
String getFilename()
返回该资源的文件名,通常是路径的最后一部分,比如:myfile.txt
public String getFilename()
实现父接口方法,这里假设该资源无文件名,直接返回了null
public String getFilename()
重写父类方法,根据classpath截取后面的文件名并返回
String getDescription()
返回该资源的描述,用于该资源在处理时的错误输出
public String getDescription()
重写父类方法,返回格式如class path resource [...]的内容
protected File getFileForLastModifiedCheck()
获取用于时间戳检查的文件,这里默认返回了getFile()
protected File getFileForLastModifiedCheck()
重写父类方法,扩展了父类方法,在getFile之前先判断url协议是否为jar/war/zip/vfszip/wsjar,如果是则获取最外层的文件URL对应的File对象,比如嵌套在war中的jar文件,则返回war文件File对象。这里判断vfs开头协议扔交给VfsResourceDelegate类来处理
public boolean equals(Object other)
重写Object的equals方法,用于比较两个Resource的Description是否相同
public boolean equals(Object other)
重写Object方法,比较类路径的值是否相同
public int hashCode()
重写Object的hashCode方法,用于获取Resource的Description值的hashCode值
public int hashCode()
重写Object方法,获取类路径classpath的hashCode值
public String toString()
重写Object的toString方法,返回Resource的Description信息
public final String getPath()
返回该资源的classpath,构造函数的path参数经过规范化处理的结果
public final ClassLoader getClassLoader()
如果指定了Class,则通过该Class获取ClassLoader,否则返回属性变量的ClassLoader参数
public InputStream getInputStream()
Resource继承了InputStreamSource接口,在ClassPathResource中得到了具体的实现,根据资源路径得到文件流

        在AbstractFileResolvingResource类中由于增加了对JBOOS的vfs文件协议的支持,因此包含了一个`VfsResourceDelegate`内部类用于获取`VfsResource`类型资源对象,该资源对象同样继承自`AbstractResource`抽象类,并针对vfs文件的特点对方法进行了重写。如下:
/**
 * Inner delegate class, avoiding a hard JBoss VFS API dependency at runtime.
 */
private static class VfsResourceDelegate {

	public static Resource getResource(URL url) throws IOException {
		return new VfsResource(VfsUtils.getRoot(url));
	}

	public static Resource getResource(URI uri) throws IOException {
		return new VfsResource(VfsUtils.getRoot(uri));
	}
}

ClassPathResource的使用:

Resource resource = new ClassPathResource("conf/custom-beans.xml");

参数path应在类路径下能够被ClassLoader所加载。

        获取到了Resource对象也就等于获取到了该资源文件,后面可以根据方法的定义对文件进行相关操作。

System.out.println(resource.getURL());
System.out.println(resource.getFilename());
System.out.println(resource.getFile().getPath());
// ... ....

你可能感兴趣的:(Spring,说源解码)