1. Resource接口
Spring对于资源加载有着一套自己的框架——Resource,Resource继承自InputStream。 下面的是Resource的源码:
public interface Resource extends InputStreamSource {
boolean exists();//判断资源是否存在
default boolean isReadable() {
return true;
}
//判断资源是否打开
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,这个类属于Java的NIO中的管道。
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
//获取内容的长度,这个方法返回一个long,因为文件内容可能很长。
long contentLength() throws IOException;
//这个方法返回的是最后修改时间,虽然也返回的是long,但是这个数字是一个时间戳。
long lastModified() throws IOException;
//这个方法根据relativePath相对路径返回一个相对与该Resource的Resource。
Resource createRelative(String relativePath) throws IOException;
@Nullable
//获取文件的名字。
String getFilename();
//获取一个对该资源的一个描述。
String getDescription();
}
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. 使用示例
使用示例如下
@Test
public void testResource() throws IOException {
String filePath = "E:\\源码\\Spring源码阅读\\testSpring\\src\\test\\resources\\spring.txt";
// 1. 使用系统的文件路径方式加载文件
WritableResource resource1 = new PathResource(filePath);
// 2. 使用类路径方式加载文件
Resource resource2 = new ClassPathResource("spring.txt");
// 3. 使用WritableResource接口写资源文件
OutputStream os = resource1.getOutputStream();
os.write("Spring是一套非常优秀的框架".getBytes());
// 4. 使用Resource接口读文件
InputStream in1 = resource1.getInputStream();
InputStream in2 = resource1.getInputStream();
BufferedInputStream bis = new BufferedInputStream(in1);
byte[] bytes = new byte[1024];
bis.read(bytes);
System.out.println(new String(bytes));
System.out.println("resource1: " + resource1.getFilename());
System.out.println("resource2: " + resource2.getFilename());
}
4. 资源路径通配符。
Resource解析各种资源路径,依靠资源路径通配符可以带来很多方便。
4.1 Ant-style Patterns
定义资源路径可以是用Ant风格的通配符,下面是 Ant-style patterns 的路径例子:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-cont?xt.xml
classpath:com/mycompany/**/applicationContext.xml
Ant风格的资源地址支持三种通配符:
- ?:匹配文件名中的一个字符
- *:匹配文件名中的多个字符
- **:匹配多层路径。
4.2 classpath*:前缀
构造基于XML的ApplicationContext,路径地址可以使用classpath*: 前缀,如下:
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
或者
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml
</param-value>
</context-param>
classpath* 和 classpath 的区别是:classpath* 会去查找所有匹配的classpath, 而classpath 只会找到第一个匹配的资源。
5. ResourceLoader
不过有个问题随之而来,那就是Resource的选择,这么多的Resource如何知道选择使用哪一个?Spring提供了一个强大的资源加载机制,他可以通过前缀标识加载资源,如:classpath:, file:,ftp:等,同时还支持使用Ant风格的通配符。
ResourceLoader用来返回Resource实例,下面是其定义:
public interface ResourceLoader {
Resource getResource(String location);
}
前缀 | 例子 | 说明 |
---|---|---|
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");
或
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xmlclasspath*:applicationContext-shiro.xml
</param-value>
</context-param>
同样的,你可以强制使用UrlResource通过添加标准的java.net.URL前缀(context-param配置的话同理):
Resource template = ctx.getResource("file:///some/resource/path/myTemplate.txt");
Resource template = ctx.getResource("https://myhost.com/resource/path/myTemplate.txt");
来源:oschina
链接:https://my.oschina.net/lscherish/blog/4329224