主要用于加载配置资源等等
Resource
前提须知
ClassLoader类的getResource和getResourceAsStream方法是原生JDK中内置的资源加载文件的方式;Spring中资源模型顶级接口不是Resource,而是InputStreamSource接口;Spring为何自己实现一套资源加载方式?主要原因是JDK原生的URL资源加载方式,对于加载classpath或ServletContext中的资源没有标准的处理。
整体结构图(非全部)
Spring中的资源模型
InputStreamSource
InputStreamSource接口只有一个getInputStream方法,实现了该接口的实现类都可以从中获取资源的输入流
Resource
Resource是InputStreamSource的子接口,它是从底层资源的实际类型(例如文件或类路径资源)中抽象出来的资源描述符的接口,它代表的是可读的资源。
EncodedResource
从类名可以看出它是编码后的资源,它的内部有个Resource类型的属性,说明它本身不是直接加载资源的
ContextResource
ContextResource是从一个封闭的上下文中加载的资源(类似于ServletContext这种)的扩展接口,例如来自javax.servlet.ServletContext,也可以来自普通的类路径路径或相对的文件系统路径(在没有显式前缀的情况下指定,因此相对于本地ResourceLoader的上下文应用)
WritableResource
支持写资源的接口,提供了输出流的访问器;它代表可写的资源
Spring中资源加载方式
ClassPathResource [classpath:/]
如果是classpath开头的资源路径,Spring解析后会自动到类路径下找;
FileSystemResource [file:/]
如果是file开头的资源路径,则会去文件系统中找;
UrlResource [xxx:/]
如果是 URL 支持的协议开头,则底层会使用对应的协议,去尝试获取相应的资源文件;
FileSystemResource
对java.io.File
的一个包装,区别在于它是订制于Spring的Resource体系下的.
ClassPathResource
ClassPathResource
表示从类路径获取的资源,通常使用线程上下文的ClassLoader进行资源加载.
我们的Web项目通常编译后,会将class文件存储在WEB-INF/classes
下,Spring就可以通过ClassPathResource
来访问这些文件.
UrlResource
UrlResource 封装了 java.net.URL,可用于访问通常可通过 URL 访问的任何对象,如文件、HTTP 目标、FTP 目标等。所有 URL 都有一个标准化的字符串表示,这样就可以使用适当的标准化前缀来表示不同的URL类型。通常有:
- file:用于访问文件系统路径
- http:用于通过http协议访问资源
- ftp:用于通过ftp访问资源
其他Resource
ServletContextResource
这是ServletContext资源的Resource实现,它解析相关Web应用程序根目录中的相对路径。
它始终支持流(stream)访问和URL访问,但只有在扩展Web应用程序存档且资源实际位于文件系统上时才允许java.io.File访问。无论它是在文件系统上扩展还是直接从JAR或其他地方(如数据库)访问,实际上都依赖于Servlet容器。
InputStreamResource
返回一个仅一次使用的流,如果你要多次使用流,不要选择它。InputStreamResource 是给定 InputStream 的资源实现。只有在没有特定的资源实现可用时,才应该使用它。特别是,尽可能选择 ByteArrayResource 或任何基于文件的资源实现。
ByteArrayResource
这是一个给定字节数组的资源实现。它为给定的字节数组创建一个 ByteArrayInputStream。它对于从任何给定的字节数组加载内容都很有用,而不必求助于一次性使用的 InputStreamResource。
ResourceLoader
整体结构图
ResourceLoader
解析
从名称来看,我们可以了解到这是一个资源加载器,也正如我们所想的,该接口是用来加载资源(例如类路径或者文件系统中的资源)的策略接口。这个接口里面只有两个接口,一个获取指定路径的资源,一个是获取资源加载器的类加载器,如图:
当然,我们也可以看到里面有一个常量,这是我们加载资源是的前缀(classpath:)
单文件加载--------------------------------------------------------
DefaultResourceLoader
作用
DefaultResourceLoader是spring提供的一个默认的资源加载器,DefaultResourceLoader实现了ResourceLoader接口,提供了基本的资源加载能力。实现了单个资源文件的加载。
DefaultResourceLoader包含了一个protocolResolvers的set集,可以通过添加ProtocolResolver来提供不同协议资源的读取能力,默认情况下protocolResolvers是空的,我们可以通过添加ProtocolResolver扩展DefaultResourceLoader的能力。
解析
如上图,这是DefaultResourceLoader实现了ResourceLoader的getResource方法,这个方法将非URL资源路径视为类路径资源(支持包含包路径的完整类路径资源名称),除非在子类重写getResourceByPath方法。我们再看getResourceByPath方法的实现:
我们可以看到,这个方法的内容是使用内部类ClassPathContextResource的,而内部类又使用了ClassPathResource,最终将路径转换成了类路径。当然,我们可以发现这个方法是protected类型的,它本身是可以被子类重写的,我们再看下图:
我们可以发现,AbstractApplicationContext是继承了DefaultResourceLoader的,所以是有可能有子类ApplicationContext重写此方法的,实际上,如果引入了spring-web模块中的依赖,这时getResourceByPath会被几个Web级的子类重写该方法,如下图,红框中都是重写的:
举个例子:
补充:ProtocolResolver
ProtocolResolver是一个函数式接口,实现该接口可以通过自定义不同的协议来读取解析资源路径中的资源。
使用示例:
在resources目录下创建一个resource目录,并在resource目录下创建一个demo.txt文件,demo.txt文件内容可以随意,当程序运行时会从该路径下加载,并通过缓冲流读取
public class DemoProtocolResolver implements ProtocolResolver {
public static final String DEMO_PATH_PREFIX = "demo:";
@Override
public Resource resolve(String location, ResourceLoader resourceLoader) {
if (!location.startsWith(DEMO_PATH_PREFIX)) {
return null;
}
String realpath = location.substring(DEMO_PATH_PREFIX.length());
String classpathLocation = "classpath:resource/" + realpath;
return resourceLoader.getResource(classpathLocation);
}
public static void main(String[] args) throws Exception {
// 实例化DefaultResourceLoader DemoProtocolResolver
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
DemoProtocolResolver demoProtocolResolver = new DemoProtocolResolver();
resourceLoader.addProtocolResolver(demoProtocolResolver);
// ResourceLoader获取编写的demo.txt
Resource resource = resourceLoader.getResource("demo:demo.txt");
InputStream inputStream = resource.getInputStream();
InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader br = new BufferedReader(reader);
String readLine;
while ((readLine = br.readLine()) != null) {
System.out.println(readLine);
}
br.close();
}
}
ClassRelativeResourceLoader
解析
ClassRelativeResourceLoader扩展的功能是可以根据给定的class所在包或者所在包的子包下加载资源。
FileSystemResourceLoader
JavaDoc
将普通路径解析为文件系统资源而不是类路径资源(后者是DefaultResourceLoader的默认策略)的ResourceLoader实现。
注意:普通路径将始终被解释为相对于当前虚拟机工作目录,即使它们以斜杠开头。(这与Servlet容器中的语义一致。)使用显式的“file:”前缀强制使用绝对文件路径。
解析
和ClassRelativeResourceLoader类似,重写了getResourceByPath方法:
ServletContextResourceLoader
作用
可以从Servlet上下文的根目录加载资源。
解析
路径:/WEB-INF/test.xml
ServletContextResourceLoader是从上下文的根路径加载资源,上下文的根路径是webapp(在开发工具中比如eclipse中,指的就是webapp,当打成war包以后就是你项目打包的名字了...);
maven工程打包以后src/main/resources下的资源文件会被打到WEB-INF/classes下,所以需要在WEB-INF后添加classes
多文件加载--------------------------------------------------------
ResourcePatternResolver
解析
从下图我们就可以看出,ResourcePatternResolver支持Ant形式的带星号( * )的路径解析,从而支持多个资源文件的加载:
PathMatchingResourcePatternResolver
我们在上面有说过Spring加载资源的三种方式,除了类路径、文件系统以及url这三种,我们还支持Ant风格路径模式的解析,PathMatchingResourcePatternResolver就是支持Ant风格路径模式解析的实现类。如图:
当然上面的是(classpath*:)这个多路径匹配模式,如果你使用的是(classpath:)的,那么你会使用DefaultResourceLoader或者你指定的资源加载器进行路径解析:
ServletContextResourcePatternResolver
解析
ServletContextResourcePatternResolver是PathMatchingResourcePatternResolver的子类,相较于PathMatchingResourcePatternResolver,ServletContextResourcePatternResolver针对ServletContextResource做了针对性处理
附录
Ant-style Patterns
Ant
(路径匹配表达式)风格的通配符解析
Pattern | Description | Example | Remark |
---|---|---|---|
? | 匹配任何的单个字符 | example/?ork | 可以匹配:example/fork ;example/work |
* | 匹配0或者任意数量的字符 | file:C:/some/path/*.xml | 可以匹配C:/some/path 下的所有xml文件 |
** | 匹配0个或者更多的目录 | classpath:com/mycompany/**/applicationContext.xml | 可以匹配mycompany和applicationContext.xml的任意目录,例如: classpath:com/mycompany/test/applicationContext.xml ; classpath:com/mycompany/work/applicationContext.xml . |
引用
https://www.cnblogs.com/coder-zyc/p/16464495.html
https://www.jianshu.com/p/646d801e055d
https://blog.csdn.net/seasonsbin/article/details/80914911