Java标准资源定位
在Java标准资源管理中有面向资源的文件系统、artifact以及远程资源(HTTP、FTP等)。它们对应Java中的ClassLoader#getResource、File以及URL或者URI。
Spring为什么要另起炉灶搞一套资源定位呢?
主要是因为Java的标准资源定位不统一,分散到不同的API中。Spring有自己的野心,他想通过自定义一套API来进行整合,忽略底层的实现差异。事实上Spring也完成了这个目的,那就是其定义的Resource接口。
![](https://i-blog.csdnimg.cn/blog_migrate/315b82b01701613ea75c6e6985e8ca35.png)
![](https://i-blog.csdnimg.cn/blog_migrate/f387ca9cb02e164fc826f5be44a7803b.png)
Talk is cheap. Show me the code
第一步:分别使用ClassPathResource、FileSystemResource以及UrlResource来进行类路径下资源、磁盘上的资源以及网络资源进行测试。这里借助apache的commons-io包中的IOUtils的toString方法来输出资源内容。
package com.tech.resources;
import org.apache.commons.io.IOUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.util.Assert;
import java.io.IOException;
import java.io.InputStream;
public class SpringResourcesManagementDemo {
public static void main(String[] args) throws IOException {
// 类路径资源管理 对应 JDK的 ClassLoader
Resource classPathResource = new ClassPathResource("default.properties");
print(classPathResource.getInputStream());
System.out.println("------------------------------分隔符---------------------------------");
// 文件系统资源管理 对应 JDK的 File
Resource fileSystemResource = new FileSystemResource("D:\\develop\\workSpace\\Coding\\" +
"spring-framework-5.0.x\\esign-spring\\src\\main\\resources\\default.properties");
print(fileSystemResource.getInputStream());
System.out.println("------------------------------分隔符---------------------------------");
// 面向流式资源管理 对应JDK的URL。这里指向的网络资源为我的博客地址
Resource urlResource = new UrlResource("https://blog.csdn.net/m0_43448868/article/details/112254608");
print(urlResource.getInputStream());
}
private static void print(InputStream is) throws IOException {
try {
Assert.state(is != null, "输入流不能为空!");
System.out.println(IOUtils.toString(is, "UTF-8"));
} catch (IOException ex) {
throw ex;
} finally {
if (is != null) {
is.close();
}
}
}
}
第二步:启动main方法查看控制台输出。
name=zhangSan
basePackages=com.xxx.spring
------------------------------分隔符---------------------------------
name=zhangSan
basePackages=com.xxx.spring
------------------------------分隔符---------------------------------
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<link rel="canonical" href="https://blog.csdn.net/m0_43448868/article/details/112254608"/>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="renderer" content="webkit"/>
<meta name="force-rendering" content="webkit"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="report" content='{"pid": "blog", "spm":"1001.2101"}'>
<meta name="referrer" content="always">
<meta http-equiv="Cache-Control" content="no-siteapp" /><link rel="alternate" media="handheld" href="#" />
<meta name="shenma-site-verification" content="5a59773ab8077d4a62bf469ab966a63b_1497598848">
<meta name="applicable-device" content="pc">
<link href="https://g.csdnimg.cn/static/logo/favicon32.ico" rel="shortcut icon" type="image/x-icon" />
<title>阿里面试题:什么是循环依赖?Spring是如何解决循环依赖的?_君战-CSDN博客</title>
<script>
可以看到无论是类路径下的资源还是磁盘中的资源以及网络资源都成功获取到了。
源码分析
ClassPathResource。这里我们只需要分析ClassPathResource的getInputStream方法即可,研究其是如何获取资源的。
// ClassPathResource#getInputStream
public InputStream getInputStream() throws IOException {
InputStream is;
if (this.clazz != null) {// 首先尝试使用传入的class的类加载器
is = this.clazz.getResourceAsStream(this.path);
} else if (this.classLoader != null) {// 其次尝试使用传入的类加载器
is = this.classLoader.getResourceAsStream(this.path);
} else {// 最后,尝试使用ClassLoader
is = ClassLoader.getSystemResourceAsStream(this.path);
}
if (is == null) {
throw new FileNotFoundException(getDescription() + " cannot be opened because it does not exist");
}
return is;
}
FileSystemResource。
// FileSystemResource#getInputStream
public InputStream getInputStream() throws IOException {
try {// 这里使用NIO中的Files工具类来创建一个ChannelInputStream
return Files.newInputStream(this.filePath);
}
catch (NoSuchFileException ex) {
throw new FileNotFoundException(ex.getMessage());
}
}
UrlResource。
// UrlResource#getInputStream
public InputStream getInputStream() throws IOException {
URLConnection con = this.url.openConnection();// 通过URL的openConnection方法来建立连接
ResourceUtils.useCachesIfNecessary(con);
try {
return con.getInputStream();
}
catch (IOException ex) {
// Close the HTTP connection (if applicable).
if (con instanceof HttpURLConnection) {
((HttpURLConnection) con).disconnect();
}
throw ex;
}
}
附录
Apache commons-io maven依赖。
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
default.properties
name=zhangSan
basePackages=com.xxx.spring