spring中资源的加载
对于资源的加载这个场景首先要划分边界,spring抽象出两个组件:Resource、ResourceLoader
Resource接口
Resource是对资源的一种抽象,提供一系列操作文件的方法
定义
- resource.java
public interface Resource extends InputStreamSource {
//文件是否存在
boolean exists();
//文件是否可读
boolean isReadable();
//文件是否打开
boolean isOpen();
//返回统一资源定位器(URL)
URL getURL() throws IOException;
//返回URI
URI getURI() throws IOException;
//返回文件
File getFile() throws IOException;
//文件最后修改时间
long lastModified() throws IOException;
//文件文件相对路径
Resource createRelative(String var1) throws IOException;
//返回文件名称
String getFilename();
//返回文件描述
String getDescription();
}
子类
类名 | 作用 |
---|---|
FileSystemResource | 对 java.io.File 类型资源的封装 |
ByteArrayResource | 对字节数组提供的数据的封装 |
UrlResource | 对 java.net.URL类型资源的封装 |
ClassPathResource | class path 类型资源的实现。使用给定的 ClassLoader 或者给定的 Class 来加载资源 |
InputStreamResource | 将给定的 InputStream 作为一种资源的 Resource 的实现类 |
AbstractResource
AbstractResource是Resource的默认抽象类,实现了大部分公共方法;
ResourceLoader
ResourceLoader定义如何加载Resource的接口
定义
public interface ResourceLoader {
/** Pseudo URL prefix for loading from the class path: "classpath:". */
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;
Resource getResource(String location);
@Nullable
ClassLoader getClassLoader();
}
-
Resource getResource(String location)
根据地址返回Resource,不保证文件是否存在,因此需要调用**exists()**进行判断 -
getClassLoader()
getClassLoader() 方法,返回 ClassLoader 实例
DefaultResourceLoader.java
@Override
public Resource getResource(String location) {
Assert.notNull(location, "Location must not be null");
//1. 首先通过ProtocolResolver来加载
for (ProtocolResolver protocolResolver : this.protocolResolvers) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
//2. 用ClassPathResource加载
if (location.startsWith("/")) {
return getResourceByPath(location);
}
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
//3. 尝试用FileUrlResource或UrlResource进行加载
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
//4. url类型加载不到,继续使用ClassPathResource方式进行加载
catch (MalformedURLException ex) {
// No URL -> resolve as resource path.
return getResourceByPath(location);
}
}
}
ProtocolResolver
ProtocolResolver用户自定义协议资源解决策略
代码演示
ResourceLoader loader = new DefaultResourceLoader();
Resource fileResource1 = loader.getResource("D:/text.txt");
Resource fileResource2 = loader.getResource("/text.txt");
Resource urlResource1 = loader.getResource("file:/Users/text.txt");
Resource urlResource2 = loader.getResource("http://www.baidu.com");
System.out.println("fileResource1.class = " + fileResource1.getClass().getSimpleName());
System.out.println("fileResource2.class = " + fileResource1.getClass().getSimpleName());
System.out.println("urlResource1.class = " + urlResource1.getClass().getSimpleName());
System.out.println("urlResource2.class = " + urlResource2.getClass().getSimpleName());
- 运行结果
由于fileResource1资源不存在,因此抛出异常,使用ClassPathResource来加载资源
FileSystemResourceLoader
FileSystemResourceLoader是对file文件的加载的优化
- getResourceByPath(String path)
protected Resource getResourceByPath(String path) {
if (path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResourceLoader.FileSystemContextResource(path);
}
对getResourceByPath方法针对file的重写,自然返回的都是FileSystemContextResource类型的Resource
ClassRelativeResourceLoader
- getResourceByPath(String path)
@Override
protected Resource getResourceByPath(String path) {
return new ClassRelativeContextResource(path, this.clazz);
}
ClassRelativeResourceLoader是针对加载ClassPathResource子类ClassRelativeContextResource文件的重写
ResourcePatternResolver
ResourcePatternResolver是针对ResourceLoader的增强,定义返回多个Resource的方法
总结
- srping通过设计出抽象的资源(Resource)和资源加载器(ResourceLoader)让加载资源这个业务场景,变的更加的边界清晰和松耦合
- AbstrctResource是Resource的抽象实现类,实现了Resource大部分接口,使用模板方法
- DefaultResourceLoader是ResourceLoader默认实现,实现了最级别的方法资源的方法,并提供了一些公共接口为子类的扩展提供便利。
- PathMatchingResourcePatternResolver实现了ResourcePatternResolver(一个允许返回多个资源文件的ResourceLoder接口),是一个比较完整的ResourceLoader