目录
一、资源抽象接口
1、传统java中的资源加载
通过ClassLoader类加载器进行的。代码如下:
Thread.currentThread().getContextClassLoader().getResource("com/demo/SimpleJava.class");
SimpleJava.class.getClassLoader().getResource("com/demo/SimpleJava.class");
ClassLoader.getSystemResource("com/demo/SimpleJava.class");
SimpleJava.class.getResource("SimpleJava.class");
每个类加载器加载资源时,都有自己固定的位置,也就是实例化类加载器时传递的url,相当于类加载器加载的资源的仓库,也只会在自己的的仓库中寻找资源,而classPath下的资源,都是AppClassLoader类进行加载。
对于通过SimpleJava.class.getResource进行的资源加载,我们可以通过分析源码:
//这是class类中进行资源加载的方法
public java.net.URL getResource(String name) {
name = resolveName(name); //通过解析资源名称,如果是以/开头,会在classpath下找寻,name必须为包含全限定名称的路径。
//上面的例子中SimpleJava.class.getResource("SimpleJava.class")的路径可以换成:/com/demo/SimpleJava.class,如果不是以/开头,则会在相对于SimpleJava.class的目录下找寻。
ClassLoader cl = getClassLoader0();
if (cl==null) {
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
2、Spring中的Resource接口
传统的Java资源文件的访问通过JDK中的File、URL类难以满足各种不同需求的资源加载,这里有Spring中设计的org.springframework.core.io.Resource接口提供更加强大的访问底层资源的能力。
下面是Resource接口的主要方法:
boolean exists():资源是否存在;
boolean isOpen():资源是否打开;
URL getURL() throws IOException:如果底层资源可以表示成URL,该方法返回对应的URL对象;
File getFile() throws IOException:如果底层资源对应一个文件,该方法返回对应的File对象;
InputStream getInputStream() throws IOException:返回资源对应的输入流;
Resource具体实现类如下:
ByteArrayResource:二进制数组表示的资源;
ClassPathResource:类路径下的资源,资源以相对于类路径的方式表示;
FileSystemResource:文件系统资源,资源以文件系统路径的方式表示;
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.file.Path、文件系统资源,它使用户能够访问任何可以同哟URL、Path、系统文件路径表示的资源,如文件系统的资源、Http资源、FTP资源;
如下分别通过FileSystemResource和ClassPathResource访问同一个文件资源:
/**
* Sping获取资源的接口
* 继承的接口有:WritableResource
* 实现类有:
* PathResource
* ClassPathResource
* FileSystemResource等
*/
@Test
public void test_resource() throws IOException {
//使用系统文件路径方式加载资源
//WritableResource接口继承接口Resource,添加了 isWritable/getOutputStream 方法
String filePath = "/Users/admin/spr-mybatis-web/src/main/resources/note/note.txt";
WritableResource res1 = new PathResource(filePath);
//使用类路径方式加载资源
Resource res2 = new ClassPathResource("note/note.txt");
//使用WritableResource接口读取资源文件
OutputStream stream1 = res1.getOutputStream();
stream1.write("这个是测试".getBytes());
stream1.close();
//使用Resource接口读取资源
InputStream ins1 = res1.getInputStream();
InputStream ins2 = res2.getInputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
int i;
while ((i = ins1.read()) != -1) {
bos.write(i);
}
System.out.println(bos.toString());
System.out.println(res1.getFilename());
System.out.println(res2.getFilename());
}
获取到资源后,可以通过getFileName()获取方法名,通过getFile()获取资源对应的File文件,通过getInputStream()直接获取文件的输入流,还可通过createRelative(String relativePath)在资源相对地址上创建新的文件。
如下是在Web应用中通过ServletContextResource以相对于Web应用根目录的方式访问文件资源:
Resource res3 = new ServletContextResource(application,"/WEB-INF/classes/conf/file1.txt");
可以通过EncodedResource对资源进行编码,保证资源内容操作的正确性,如下:
Resource res = new ClassPathResource("conf/file1.txt");
EncodedResource encRes = new EncodedResource(res,"UTF-8");
String content = FileCopyUtils.copyToString(encRes.getReader());
System.out.println(content);
二、资源加载
为了访问不同类型的资源,必须使用相应的Resorce实现类,这是比较麻烦的,spring提供了一个强大的加载资源的机制,能够自动识别不同的资源类型。
1、资源地址表达式
地址前缀 | 示例 | 对应的资源类型 |
classpath: | classpath:com/bean/bean.xml | 表示从类路径加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。资源文件可以在标准的文件系统中,也可以在jar或zip的类包中 |
file: | file:/com/bean/bean.xml | 使用UrlResource从文件系统目录中装载资源,可采用绝对或相对路径 |
http:// | http://www.csdn.bean.xml | 使用UrlResource从Web服务器中装载资源 |
ftp:// | ftp://www.csdn.bean.xml | 使用UrlResource从FTP服务器中装载资源 |
没有前缀 | com/bean/bean.xml | 根据ApplicationContext的具体实现类采用对应类型的Resource |
其中,classpath:和classpath*:的区别在于classpath*:会扫描所有类路径下出现的资源,而classpath只会在第一个加载的包下查找,即就是只加载一个资源文件。
匹配风格资源地址支持3种:
?:匹配文件中的一个字符
* :匹配文件中的任意字符
** :匹配多层路径
如:file:/com/bean/bea?.xml
2、资源加载器
Spring定义了一套资源加载的接口,并提供了实现类。
2-1、Resource接口
位于包 org.springframework.core.io 下,提供了一些基本方法,如 exists()/getResource()等方法
2-2、ResourcePatternResolver接口
位于包 org.springframework.core.io.support 下,继承了接口ResourceLoader,增加了Resource[] getResources(String var1)方法,可以看出相对与ResourceLoader接口而言增加了批量加载文件方法。添加了资源匹配模式表达式,但不支持匹配风格地址加载资源。
2-3、PathMatchingResourcePatternResolver类
位于包 org.springframework.core.io.support 下,实现了接口 ResourcePatternResolver。新增了支持匹配风格地址加载资源。
具体代码如下:
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resourcePatternResolver.getResources("classpath*:note/not?.txt");
for(Resource resource:resources){
System.out.println(resource.getFilename());
}
三、总结
1、传统java中的资源加载,是通过类加载器进行获取资源;
2、Spring获取资源提供了Resource接口,该接口提供了获取资源的及其相关方法,并针对不同资源获取方式提供了不同的实现类;
3、为了访问不同类型的资源,必须使用相应的Resorce实现类,这是比较麻烦的,spring提供了一个强大的加载资源的机制,能够自动识别不同的资源类型。Spring为其提供了资源表达式和资源加载器接口和实现类。