资源访问的方式
非Spring 方式
-
ClassLoader
类加载器加载资源:ClassLoader.getResourceAsStream()
,从ClassPath
根路径下获取,注意路径不能以’/’ 开头 -
Class
类加载资源:Class.getResourceAsStream(String path)
path
参数不以/
开头,就是针对当前的类,是从此类所在的包下获取资源path
参数以/
开头,则是从根路径ClassPath
下获取资源
- Servlet上下文容器
ServletContext
加载资源:servletContext.getResourceAsStream(String path)
,默认从 Web 应用根目录下取资源,path
建议加上/
Spring 方式
Spring 提供了资源访问接口(Resource
)与资源加载机制(ResourceLoader
)两种方式,用于资源的加载功能。
资源抽象接口
资源接口设计
-
InputStreamSource
是Spring资源加载的基础接口,该接口定义了getInputStream()
方法,用于获取文件的输入流,调用这个方法会得到一个新的资源输入流流 -
org.springframework.core.io.Resource
接口实现了InputStreamSource
接口,在 Spring 中负责装载各种资源,包括文件资源、外部文件资源、国际化属性文件等,并且可以脱离Spring 单独使用。统一的Resource
接口可以使用EncodedResource
进行编码,以保证内容操作的正确性 -
该接口的部分主要方法,如下
方法 | 描述 |
---|---|
boolean exists(); | 判断资源是否存在 |
boolean isReadable(); | 判断资源是否可读 |
boolean isOpen(); | 判断资源是否打开 |
URL getURL() | 如果底层资源可以表示成URL ,这该方法返回对应的URL对象 |
File getFile() | 如果底层资源对应一个文件,这该方法返回对应File对象 |
InputStream getInputStream() | 返回资源对应的输入流 |
Resource
接口的主要实现
实现类 | 描述 |
---|---|
WritableResource | 可写资源接口。主要有FileSystemResource 和PathResource 两个实现 |
FileSystemResource | 文件系统资源,如D://conf/bean/xml |
PathResource | 支持Path、Url 、系统文件路径等表示的资源(spring4.x新增) |
InputStreamResource | 以输入流返回表示的资源 |
ByteArrayResource | 二进制数组表示的资源 |
ClassPathResource | ClassPath 路径下的资源,相对路径存在,常用 |
UrlResource | 通过 Url 地址访问资源 |
ServletContextResource | Web上下文访问资源。负责相对于 Web 应用根目录的路径加载资源 |
- 类图如下
简单应用
ClassPathResource
,获取ClassPath
路径下的资源,使用EncodedResource
对资源进行编码
ClassPathResource classPathResource = new ClassPathResource("spring-context.xml");
String filename = classPathResource.getFilename();
System.out.println("Filename: " + filename);
// spring-context.xml
String path = classPathResource.getPath();
System.out.println("Path:" + path);
// 使用 EncodedResource 对资源进行编码
EncodedResource encodedResource = new EncodedResource(classPathResource, Charset.defaultCharset());
Reader reader = encodedResource.getReader();
String s = FileCopyUtils.copyToString(reader);
System.out.println(s);
FileSystemResource
,获取文件系统资源
FileSystemResource fileSystemResource = new FileSystemResource("G:\\WorkSpace\\Sam\\Learning\\Learning-Spring\\spring-ioc\\src\\main\\resources\\spring-context.xml");
String filename = fileSystemResource.getFilename();
System.out.println(filename);
// G:/WorkSpace/Sam/Learning/Learning-Spring/spring-ioc/src/main/resources/spring-context.xml
String path = fileSystemResource.getPath();
System.out.println(path);
// 使用 EncodedResource 对资源进行编码
EncodedResource encodedResource = new EncodedResource(fileSystemResource, Charset.forName("UTF-8"));
Reader reader = encodedResource.getReader();
String s = FileCopyUtils.copyToString(reader);
System.out.println(s);
资源加载器
访问不同类型的资源,使用相应的 Resource 实现类,如访问ClassPath
下的资源使用ClassPathResource
,而web根路径下的资源就需要ServletContextResource
。这其实不是很方便。Spring 提供了一个强大的加载资源的机制,直接可以通过classpath:
、file:
等资源地址前缀、或者是带有Ant
风格通配符地址资源自动加载
地址资源表达式
- 资源类型的地址前缀
地址前缀 | 对应的资源类型 |
---|---|
classpath: | 从类路径加载资源。classpath:和classpath:/ 是等价的,都是相对于类的根路径。classpath*: 多个jar包中的同一个包名,全部加载 |
file: | 使用 `UrlResource 装载,可采用绝对或相对路径 |
http:// | 使用 UrlResource 从web 服务器中装载 |
ftp:// | 使用 UrlResource 从FTP服务器中装载 |
无前缀 | 根据 ApplicationContext 的具体实现类采用相应类型的 Resource |
- Ant 风格的资源路径
通配符 | 描述 |
---|---|
? | 匹配文件名中的一个字符 |
* | 匹配文件名中的任意字符 |
** | 匹配多层路径 |
资源加载器
-
Spring 定义了一套资源加载的接口
org.springframework.core.io.ResourceLoader
,用于资源接口Resource
和类加载器的获取。 -
在接口上基础上,Spring实现了多个实现类
资源加载器 | 描述 |
---|---|
DefaultResourceLoader | 默认实现,一般解析器为类路径资源。 如果参数 location 是URL ,返回UrlResource ;如果是非URL路径或是 classpath: 伪URL ,则返回ClassPathResource |
FileSystemResourceLoader | 将普通路径解析为文件系统资源。使用显式的file: 前缀来强制执行绝对文件路径 |
ServletContextResourceLoader | 将路径解析为ServletContext 资源 |
ResourcePatternResolver | 新增了 Resource[] getResources(String locationPattern) 方法 |
PathMatchingResourcePatternResolver | Spring 提供的标准实现类,支持类型前缀以及Ant风格的资源路径表达式。可以应用在如手动加载 mybatis 的 mapperLocations 。 |
ApplicationContext | Spring上下文容器,其内部加载资源也是同样的机制 |
- 类图如下:
简单应用
PathMatchingResourcePatternResolver
简单示例:
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
// 默认使用 DefaultResourceLoader.getResource()
// 1- "/" 开头,ClassPathContextResource
// 2- "classpath:"开头,ResourceUtils.CLASSPATH_URL_PREFIX封装了常量,使用 ClassPathResource
// 3- 其他使用 UrlResource
// 4- 异常(如相对地址):ClassPathContextResource
Resource resource = resolver.getResource("classpath:spring-context.xml");
EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
Reader reader = encodedResource.getReader();
String s = FileCopyUtils.copyToString(reader);
System.out.println(s);
// classpath*:不同jar包中,都有com.learning 包名,classpath加载第一个,classpath* 会加载多个
// classpath*:/mapper/**/*Mapper.xml
Resource[] resources = resolver.getResources("classpath*:spring-context.xml");
总结
Spring 提供的这套资源访问接口(Resource
)与资源加载机制(ResourceLoader
)是整个Spring容器的基础,脱离Spring一样非常有用