1. Resource接口
Spring对于资源加载有着一套自己的框架——Resource,Resource继承自InputStream。
下面的是Resource的源码:
1 | public interface Resource extends InputStreamSource { |
2. Resource实现类
你可以理解为,Resource就是一个增强版的InputStreamSource,Resource 接口是Spring资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成——每个实现类代表一种资源访问策略(策略模式)。
- UrlResource:
- UrlResource封装了java.net.URL,可用于访问通常可通过url访问的任何对象,如文件、HTTP目标、FTP目标和其他对象。所有URL可以使用一个标准化前缀来表示一个URL类型。例如: file:用于访问文件系统路径。 http:用于通过HTTP协议访问资源。 ftp:用于通过FTP访问资源。
- ClassPathResource:
- 表示从类路径加载资源。如果资源路径带上前缀ClassPath:,那么会隐式的解析为ClassPathResource。注意,如果类资源文件是在文件系统中,则该资源实现会被解析为java.io.File, 如果是在Jar包中,则会使用java.net.URL来解析。
- FileSystemResource:
- 他是java.io.File和java.nio.file.Path的Resource实现,支持解析为File或者URL。如D:/aaa/vvv.java
- ServletContextResource:
- 这是ServletContext的Resource实现,用于解释相关Web应用程序根目录中的相对路径。访问Web容器上下文中的资源而设计的类,负责对于Web应用根目录的路径加载资源。它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File方式访问。该类还可以直接从JAR包中访问资源。
- InputStreamResource:
- InputStreamResource 是InputStream 的Resource实现。只有在其他Resource实现不可用的时候才考虑使用它。和其他的Resource实现相反,它是一个already-opened resource的描述器,所以isOpen()会返回true。 如果你想保存资源描述器或者多次读取一个stream, 那么不要使用它。
- ByteArrayResource:
- 是byte array的Resource实现, 它创建了ByteArrayInputStream。它对于从任何给定的字节数组加载内容都很有用,而不必求助于单次使用的InputStreamResource。
- PathResource:
- Spring4.0提供的读取资源文件的新类。Path封装了java.net.URL、java.nio.Path、文件系统资源,它使用户能够访问任何可以通过URL、Path、系统文件路径表示的资源,如文件系统的资源,HTTP资源、FTP资源等。
3. 使用示例
使用示例如下
1 | @Test |
4. 资源路径通配符。
Resource解析各种资源路径,依靠资源路径通配符可以带来很多方便。
4.1 Ant-style Patterns
定义资源路径可以是用Ant风格的通配符,下面是 Ant-style patterns 的路径例子:
1 | /WEB-INF/*-context.xml |
Ant风格的资源地址支持三种通配符:
- ?:匹配文件名中的一个字符
- *:匹配文件名中的多个字符
- **:匹配多层路径。
4.2 classpath*:前缀
构造基于XML的ApplicationContext,路径地址可以使用classpath*: 前缀,如下:
1 | ApplicationContext ctx = |
或者
1 | <context-param> |
classpath* 和 classpath 的区别是:classpath* 会去查找所有匹配的classpath, 而classpath 只会找到第一个匹配的资源。
5. ResourceLoader
不过有个问题随之而来,那就是Resource的选择,这么多的Resource如何知道选择使用哪一个?Spring提供了一个强大的资源加载机制,他可以通过前缀标识加载资源,如:classpath:, file:,ftp:等,同时还支持使用Ant风格的通配符。
ResourceLoader用来返回Resource实例,下面是其定义:
1 | public interface ResourceLoader { |
前缀 | 例子 | 说明 |
---|---|---|
classpath: | classpath:com/myapp/config.xml | 使用ClassPathResource从classpath中加载。 |
file: | file:/data/config.xml | 作为 URL 加载。使用UrlResource从文件系统目录中装载资源 |
http: | http://myserver/logo.png | 作为 URL 加载。使用UrlResource从Web服务器中装载资源 |
ftp: | ftp://www.mcwebsite.top/bean.xml | 作为 URL 加载。使用UrlResource从ftp服务器中装载资源 |
(none) | /data/config.xml | 根据ApplicationContext的具体实现选择对应类型的Resource |
上表中最后一种情况,需要说明下:
所有的ApplicationContext都实现了ResourceLoader类。因此所有的ApplicationContext都可以用来获取Resource。
当在特定的应用程序上下文上调用getResource(),并且指定的位置路径没有特定的前缀时,将返回适合该特定应用程序上下文的资源类型。
例如,假设对ClassPathXmlApplicationContext实例执行了以下代码片段:
Resource template = ctx.getResource("some/resource/path/myTemplate.txt");
在ClassPathXmlApplicationContext中,这个方法返回ClassPathResource。
以此类推,在FileSystemXmlApplicationContext中,方法返回FileSystemResource。在WebApplicationContext, 方法返回ServletContextResource。
当然,就像我们表中说的,我们可以强制使用ClassPathResource,而不管ApplicationContext到底是什么。这样做的话,我们需要添加classpath:前缀。如下:
Resource template = ctx.getResource("classpath:some/resource/path/myTemplate.txt");
或
1 | <context-param> |
同样的,你可以强制使用UrlResource通过添加标准的java.net.URL前缀(context-param配置的话同理):
1 | Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt"); |