“我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情”
Resource
需要处理不同类型的外部资源(URL、File、ClassPath等等),而且处理这些资源步骤都是类似的(打开资源,读取资源,关闭资源)。Spring提供Resource接口来统一这些底层资源一致的访问,作为所有资源的统一抽象。
Resource体系
Resource
public interface Resource extends InputStreamSource {
/**
* 当前Resource资源是否存在
*/
boolean exists();
/**
* 当前Resource是否可读
*/
default boolean isReadable() {
return exists();
}
/**
* 当前Resource是否已经打开,如果返回true,则只能被读取一次然后关闭以避免资源泄露;
* 常见的Resource实现一般返回false
*/
default boolean isOpen() {
return false;
}
/**
* 是否为文件资源
*/
default boolean isFile() {
return false;
}
/**
* 如果当前Resource代表的资源能由java.util.URL代表,则返回该URL,否则抛出IOException
*/
URL getURL() throws IOException;
/**
* 如果当前Resource代表的资源能由java.util.URI代表,则返回该URL,否则抛出IOException
*/
URI getURI() throws IOException;
/**
* 如果当前Resource代表的底层资源能由java.io.File代表,则返回该File,否则抛出IOException
*/
File getFile() throws IOException;
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
/**
* 返回当前Resource代表的底层文件资源的长度,一般是值代表的文件资源的长度
*/
long contentLength() throws IOException;
/**
* 返回当前Resource代表的底层资源的最后修改时间
*/
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
/**
* 返回当前Resource代表的底层文件资源的文件路径,比如File资源“file://d:/test.txt”将返回“d:/test.txt”;
* 而URL资源http://www.baidu.cn将返回null,因为只返回文件路径
*/
@Nullable
String getFilename();
/**
* 返回当前Resource代表的底层资源的描述符,通常就是资源的全路径(实际文件名或实际URL地址)
*/
String getDescription();
}
- ByteArrayResource:对于字节数组的实现,为其构造一个ByteArrayInputStream;
- ClassPathResource:ClassPath类型资源的实现,使用指定的Class或ClassLoader加载资源。用来访问类加载路径下的资源,该种类型在Web应用中可以自动搜索位于WEB-INF/classes下的资源文件,而无需使用绝对路径访问;
- InputStreamResource:InputStream的实现,如果需要将资源描述符保存在某处,或者如果需要从流中多次读取,不要使用InputStreamResource;
- UrlResource:对于java.net.URL类型资源的实现,支持File和URL的形式,既可以访问网络资源,也可以访问本地资源,加不同的前缀即可;
- FileSystemResource:对java.io.File类型和java.nio.file.Path资源的封装,支持File和URL的形式。实现了WritableResource接口,支持对资源的写操作;
- EncodedResource:实现对文件编码类型的处理。
它们都继承抽象类AbstractResource,AbstractResource实现了Resource接口。自定义Resource只需继承AbstractResource抽象类,它已经实现Resource接口的大部分公共实现,再根据自定义的资源特性覆盖相应的方法。
ResourceLoader
Resource定义统一的资源,ResourceLoader加载资源。
ResourceLoader体系
DefaultResourceLoader
public class DefaultResourceLoader implements ResourceLoader {
......
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
// 是否有自定义协议策略
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
// 以“/”开头,构造返回ClassPathContextResource
if (location.startsWith("/")) {
return getResourceByPath(location);
}
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
// 以"classpath:"开头,构造返回ClassPathResource
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
// 否则构造URL地址
try {
URL url = new URL(location);
// 如果是FileURL,构造返回FileUrlResource,否则构造返回UrlResource
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
//构造URL失败(不符合URL规范),当作普通路径处理
return getResourceByPath(location);
}
}
}
......
}
ProtocolResolver
用户自定义协议资源解决策略,作为DefaultResourceLoader的SPI,允许用户自定义资源加载协议,而不需要继承ResourceLoader的子类。实现ProtocolResolver接口。
public class MyProtocolResolver implements ProtocolResolver {
@Override
public Resource resolve(String location,
ResourceLoader resourceLoader) {
System.out.println("自定义加载资源......");
FileSystemResourceLoader fileSystemResourceLoader = new FileSystemResourceLoader();
return fileSystemResourceLoader.getResource("D:\\IDEAProbject\\openSources\\spring-framework\\gradle\\docs.gradle");
}
}
public class Demo {
public static void main(String[] args) {
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
resourceLoader.addProtocolResolver(new MyProtocolResolver());
Resource resource = resourceLoader.getResource("/");
System.out.println(resource.getFilename()); //docs.gradle
System.out.println(resource.getDescription()); //file [D:\IDEAProbject\openSources\spring-framework\gradle\docs.gradle]
}
}
ResourcePatternResolver——ResourceLoader接口的增强
public interface ResourcePatternResolver extends ResourceLoader {
/**
* 支持classpath*:形式路径匹配,即Ant风格;允许使用通配符来对路径进行匹配。"classpath*:"可以返回路径下所有满足条件的资源实例
*/
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
/**
* 支持根据路径匹配模式返回多个 Resource 实例
*/
Resource[] getResources(String locationPattern) throws IOException;
}
PatchMatchingResourcePatternResolver
ResourcePatternResolver最常用的子类
public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
// 负责对基于字符串的路径和指定的模式符号进行匹配
private PathMatcher pathMatcher = new AntPathMatcher();
/**
* 实例化一个DefaultResourceLoader,继承自ResourceLoader的方法委托给内部的DefaultResourceLoader实现
* PathMatchingResourcePatternResolver只负责处理实现ResourcePatternResolver中的方法
*/
public PathMatchingResourcePatternResolver() {
this.resourceLoader = new DefaultResourceLoader();
}
}