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




classpathresource依赖pom文件 class path resource_Java


        然后以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文件中的资源除外)。其继承实现关系图如下:



classpathresource依赖pom文件 class path resource_Java_02


        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());
// ... ....