一、InputStreamSource接口
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
二、Resource接口
public interface Resource extends InputStreamSource {
//判断资源是否存在
boolean exists();
//判断资源是否可读
default boolean isReadable() {
return exists();
}
//判断资源是否打开
default boolean isOpen() {
return false;
}
//判断资源是否是一个文件
default boolean isFile() {
return false;
}
//获取资源对应的URL
URL getURL() throws IOException;
//获取资源对应的URI
URI getURI() throws IOException;
//获取资源对应的File
File getFile() throws IOException;
//将资源转换为ReadableByteChannel
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
//获取资源的大小
long contentLength() throws IOException;
//获取资源的最后修改时间
long lastModified() throws IOException;
//根据当前资源创建一个相对资源。
Resource createRelative(String relativePath) throws IOException;
//获取文件名。
@Nullable
String getFilename();
//在资源出错时,详细打印出出错的文件。
String getDescription();
}
对于不同来源的资源文件都有相应的实现:文件(FileSystemResource)、ClassPath资源(ClassPathResource)、URL资源(UrlResource)、InputStream资源(InputStreamResource)、Byte数组(ByteArrayResource)等
重点看ClassPathResource的实现方式
public ClassPathResource(String path) {
this(path, (ClassLoader) null);
}
public ClassPathResource(String path, @Nullable 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());
}
public ClassPathResource(String path, @Nullable Class<?> clazz) {
Assert.notNull(path, "Path must not be null");
this.path = StringUtils.cleanPath(path);
this.clazz = clazz;
}
@Deprecated
protected ClassPathResource(String path, @Nullable ClassLoader classLoader, @Nullable Class<?> clazz) {
this.path = StringUtils.cleanPath(path);
this.classLoader = classLoader;
this.clazz = clazz;
}
ClassPathResource的构造方法有4个,一个已经过期。另外三个,我们一般调用一个参数的构造函数,即传入文件路径即可,它内部会调用另外一个重载的方法,给classloader赋值(因为后面要通过classloader去读取文件)。
- 在 ClassPathResource 初始化的过程中,会先调用 StringUtils.cleanPath 方法对传入的路径进行清理,所谓的路径清理,就是处理路径中的相对地址、Windows 系统下的 \ 变为 / 等。
- getPath 方法用来返回文件路径,这是一个相对路径,不包含 classpath。
- resolveURL 方法表示返回资源的 URL,返回的时候优先用 Class.getResource 加载,然后才会用 ClassLoader.getResource 加载,关于 Class.getResource 和 ClassLoader.getResource 的区别大概说下,Class.getResource 最终还是会调用 ClassLoader.getResource,只不过 Class.getResource 会先对路径进行处理。
- getInputStream 读取资源,并返回 InputStream 对象。
- createRelative 方法是根据当前的资源,再创建一个相对资源。
构造出Resource对象之后,还会把Resource对象转换为EncodedResource,这里会对资源进行编码处理,只要体现在getReader方法上,在获取Reader对象时,如果有编码,则给出编码格式:
//org.springframework.core.io.support.EncodedResource
public Reader getReader() throws IOException {
if (this.charset != null) {
return new InputStreamReader(this.resource.getInputStream(), this.charset);
}
else if (this.encoding != null) {
return new InputStreamReader(this.resource.getInputStream(), this.encoding);
}
else {
return new InputStreamReader(this.resource.getInputStream());
}
}
在这之后,就是通过XmlBeanDefinitionReader 去加载Resource了