Spring中资源加载的框架
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 getURL() throws IOException;
URI getURI() throws IOException;
File getFile() throws IOException;
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
@Nullable
String getFilename();
String getDescription();
}
-
exists()
判断资源是否存在 -
isOpen()
判断资源是否打开 -
isFile()
判断资源是否是一个文件 -
getURL()
获取资源文件的URL -
getURI()
获取资源文件的URI -
readableChannel()
这个方法接口中有默认实现,返回的是ReadableByteChannel,这个类属于Java的NIO中的管道。 -
contentLength()
获取内容的长度,这个方法返回一个long,因为文件内容可能很长。 -
lastModified()
这个方法返回的是最后修改时间,虽然也返回的是long,但是这个数字是一个时间戳。 -
createRelative(String relativePath)
这个方法根据relativePath返回一个相对与该Resource的Resource。 -
getFilename()
获取文件的名字。 -
getDescription
获取一个对该资源的一个描述。
下面的是Resource的继承图:(这里只是一部分)
Resource的继承图.png
- WritableResource:可写资源接口,是Spring3.1版本新增的接口,有两个实现类FileSystemResource和PathResource,其中PathResource是Spring4.0提供的实现类。
- ByteArrayResource:二进制数组表示的资源,二进制数组资源可以在内存中通过程序构造。
- ClassPathResource:类路径下的资源,资源以相对路径的方式表示。
- FileSystemResource:文件系统资源,资源一文件系统的路径表示,如D:/aaa/vvv.java
- InputStreamResource:以输入流表示返回的资源。
- ServletContextResource:问访问Web容器上下文中的资源而设计的类,负责对于Web应用根目录的路径加载资源。它支持以流和URL的方式访问,在WAR解包的情况下,也可以通过File方式访问。该类还可以直接从JAR包中访问资源。
- UrlResource:URL封装了java.net.URL,它使用户能够访问任任何可以通过URL表示的资源,如文件系统的资源、HTTP资源、FTP资源等。
- PathResource:Spring4.0提供的读取资源文件的新类。Path封装了java.net.URL、java.nio.Path、文件系统资源,它使用户能够访问任何可以通过URL、Path、系统文件路径表示的资源,如文件系统的资源,HTTP资源、FTP资源等。
和JDK提供的File类访问资源比起来,Spring的Resource实现类提供了更加便捷的访问方式,用户可以根据实际的情况选择合适的Resource访问资源。下面的是一个示例:
package top.mcwebsite.resource;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.PathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import java.io.*;
public class FileResourceTest {
@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());
}
}
随之而来的问题及解决
那就是Resource的选择,这么多的Resource如何知道选择使用哪一个?Spring提供了一个强大的资源加载机制,,他可以通过前缀标识加载资源,如:classpath, file等,同时还支持使用Ant风格的通配符。
- 资源地址的表示
地址前缀 | 示例 | 对应的资源类型 |
---|---|---|
classpath: | classpath:top/mcwebsite/resource/bean.xml | 从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的路径。资源文件可以在标准的文件系统中,也可以在JAR和ZIP的类包中 |
file: | file:/config/bean,xml | 使用UrlResource从文件系统目录中装载资源,可采用绝对或相对路径 |
http:// | http://www.mcwebsite.top/bean.xml | 使用UrlResource从Web服务器中装载资源 |
ftp:// | ftp://www.mcwebsite.top/bean.xml | 使用UrlResource从ftp服务器中装载资源 |
没有前缀 | com/mcwebsite/resource/bean.xml | 根据ApplicationContext的具体实现曹勇对应类型的Resource |
关于classpath:和classpath:前缀。如果有多个JAR包或文件系统路径都拥有同一个相同的包。classpath:只会找到第一个加载的,而classpath:会扫描所有的这些JAR包及类路径下出现的。
Ant风格的资源地址支持三种通配符:
- ?:匹配文件名中的一个字符
- *:匹配文件名中的多个字符
- **:匹配多层路径。
ResourceLoader接口仅有一个getResource(String location)方法,可根据资源地址加载资源。不过,资源地址仅支持带资源类型前缀的表达式,不支持Ant风格的资源路径表达式。ResourcePatternResolver扩展ResourceLoader接口,定义了一个新的接口方法getResources(String locationPatern),该方法支持带资源前缀及Ant风格的资源路径表达式。
import java.io.IOException;
import static org.junit.Assert.assertNotNull;
public class PatternResolverTest {
@Test
public void getResources() throws IOException {
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath:*.xml");
assertNotNull(resources);
for (Resource resource : resources) {
System.out.println(resource.getDescription());
}
}
}
网友评论