概述

对于每一个底层资源,比如文件系统中的一个文件,classpath上的一个文件,或者一个以URL形式表示的网络资源,Spring 统一使用 Resource 接口进行了建模抽象,相应地,对于这些资源的加载,Spring使用了 ResourceLoader 进行了统一建模抽象。

通过ResourceLoader,给定其可以接受的资源路径,我们可以获得对应资源的Resource对象,然后进行进行相应的资源访问。

Spring提供了一个缺省的ResourceLoader实现DefaultResourceLoader。该实现类可以加载classpath或者文件系统中的某个文件,或者URL形式存在的某个网络资源。Spring的各种应用上下文都间接地通过基类AbstractApplicationContext继承自DefaultResourceLoader,所以这些应用上下文自身具备并且使用DefaultResourceLoader所定义资源加载能力。

本文我们先看一下接口ResourceLoader本身,然后通过一些例子看ResourceLoader/DefaultResourceLoader如果使用。

ResourceLoader接口定义

package org.springframework.core.io;

import org.springframework.lang.Nullable;
import org.springframework.util.ResourceUtils;

public interface ResourceLoader {

/** Pseudo URL prefix for loading from the class path: "classpath:". */
// 从 classpath 上加载资源的伪URL前缀: classpath:
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

/**
* 给定资源路径,返回相应的资源Resource对象。所返回的Resource对象,
* 也可以叫做资源句柄,必须是可重用的资源描述符,允许多次在其上
* 调用方法Resource#getInputStream()。
* 另外 :
*
* 1. 必须支持全路径URL : 比如 "file:C:/test.dat".
* 2. 必须支持classpath伪URL : 比如 "classpath:test.dat".
* 3. 应该支持相对文件路径:比如 "WEB-INF/test.dat". (实现相关)
*
* 注意 : 所返回的资源句柄并不意味着对应的资源是已经存在的,所传入的参数
* 只是一个资源路径,并不代表相应的资源已经存在;使用者必须调用方法Resource#exists
* 来判断对应资源的存在性。
* @param location 资源路径
* @return 相应的资源句柄,总是不为null(哪怕对应的资源不存在)
*/
Resource getResource(String location);

/**
* 暴露当前ResourceLoader所使用的ClassLoader给外部。
*/
@Nullable
ClassLoader getClassLoader();

}

缺省实现DefaultResourceLoader的使用

@Slf4j
public class SpringDefaultResourceLoaderDemo {
/**
* 描述一个Resource实例
*
* @param resource
* @throws Exception
*/
void describe(Resource resource) throws Exception {
log.info("====================================");
log.info("toString : {}", resource.toString());
log.info("contentLength : {}", resource.contentLength());
log.info("exists : {}", resource.exists());
log.info("getDescription : {}", resource.getDescription());
log.info("isReadable : {}", resource.isReadable());
log.info("isOpen : {}", resource.isOpen());
log.info("getFilename : {}", resource.getFilename());
log.info("isFile : {}", resource.isFile());
if (resource.isFile()) {
// getFile()仅针对文件类型Resource有效,可以是文件系统文件或者classpath上的文件
log.info("getFile : {}", resource.getFile());
}

if (!((resource instanceof ByteArrayResource) || (resource instanceof InputStreamResource))) {
// 以下三个属性针对 ByteArrayResource/InputStreamResource 类型资源无效,调用的话会抛出异常
log.info("lastModified : {}", resource.lastModified());
log.info("getURI : {}", resource.getURI());
log.info("getURL : {}", resource.getURL());
}
}

@Test
public void test() throws Exception {
ResourceLoader resourceLoader = new DefaultResourceLoader();
{// 获取 classpath 上的某个资源 : 路径带前缀 classpath:
Resource resource = resourceLoader.getResource(
"classpath:test/resources/SpringDefaultResourceLoaderDemo.class");
describe(resource);
}

{// 获取 classpath 上的某个资源 : 路径不带前缀 classpath:
Resource resource = resourceLoader.getResource(
"test/resources/SpringDefaultResourceLoaderDemo.class");
describe(resource);
}

{// 获取 classpath 上的某个资源 : 路径前缀为/,而不是 classpath:
Resource resource = resourceLoader.getResource(
"/test/resources/SpringDefaultResourceLoaderDemo.class");
describe(resource);
}

{// 获取网络上指定 url 的某个资源
Resource resource = resourceLoader.getResource(
"https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference"
+"/pdf/spring-framework-reference.pdf");
describe(resource);
}

{// 获取文件系统中的某个资源
// test.txt 是当前磁盘卷根目录下一个存在的文件,内容是:Test Spring Resource
Resource resource = resourceLoader.getResource("file:/test.txt");
describe(resource);
}
}
}

上面的测试代码执行输出如下:

====================================
toString : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
contentLength : 3011
exists : true
getDescription : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
isReadable : true
isOpen : false
getFilename : SpringDefaultResourceLoaderDemo.class
isFile : true
getFile : D:\idea_wks\springboot-tut-zero\target\test-classes\test\resources\SpringDefaultResourceLoaderDemo.class
lastModified : 1546249104715
getURI : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
getURL : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
====================================
toString : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
contentLength : 3011
exists : true
getDescription : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
isReadable : true
isOpen : false
getFilename : SpringDefaultResourceLoaderDemo.class
isFile : true
getFile : D:\idea_wks\springboot-tut-zero\target\test-classes\test\resources\SpringDefaultResourceLoaderDemo.class
lastModified : 1546249104715
getURI : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
getURL : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
====================================
toString : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
contentLength : 3011
exists : true
getDescription : class path resource [test/resources/SpringDefaultResourceLoaderDemo.class]
isReadable : true
isOpen : false
getFilename : SpringDefaultResourceLoaderDemo.class
isFile : true
getFile : D:\idea_wks\springboot-tut-zero\target\test-classes\test\resources\SpringDefaultResourceLoaderDemo.class
lastModified : 1546249104715
getURI : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
getURL : file:/D:/idea_wks/springboot-tut-zero/target/test-classes/test/resources/SpringDefaultResourceLoaderDemo.class
====================================
toString : URL [https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/pdf/spring-framework-reference.pdf]
contentLength : 5762367
exists : true
getDescription : URL [https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/pdf/spring-framework-reference.pdf]
isReadable : true
isOpen : false
getFilename : spring-framework-reference.pdf
isFile : false
lastModified : 1496863570000
getURI : https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/pdf/spring-framework-reference.pdf
getURL : https://docs.spring.io/spring/docs/4.3.9.RELEASE/spring-framework-reference/pdf/spring-framework-reference.pdf
====================================
toString : URL [file:/test.txt]
contentLength : 20
exists : true
getDescription : URL [file:/test.txt]
isReadable : true
isOpen : false
getFilename : test.txt
isFile : true
getFile : \test.txt
lastModified : 1542633020067
getURI : file:/test.txt
getURL : file:/test.txt

总结

上面的例子演示了DefaultResourceLoader的使用方法和效果,实际上,DefaultResourceLoader使用方法可以总结如下:

用户为DefaultResourceLoader提供自定义的ProtocolResolver用来识别特定格式的资源路径,
使用方法DefaultResourceLoader#addProtocolResolver添加ProtocolResolver,可以提供多个,也可以不提供。
缺省情况下,DefaultResourceLoader不包含ProtocolResolver。
给定一个路径,调用方法DefaultResourceLoader#getResource获取资源对象(也可以叫做句柄)
DefaultResourceLoader会以以下顺序识别路径 :
轮询每个ProtocolResolver看它们哪个可以处理该路径,如果可以让其处理并返回相应的资源句柄;
如果路径以"/"开头,尝试将其处理为一个ClassPathContextResource句柄并返回;
如果路径以"classpath:"前缀开头,去除路径中前缀部分之后将其封装成一个ClassPathResource句柄并返回;
如果路径是URL格式
如果路径以"file:"/“vfs:”/"vfsfile:"前缀开头,将其封装成一个FileUrlResource句柄并返回;
否则将其封装成一个UrlResource句柄返回;
其他格式,仍然尝试将其封装一个ClassPathContextResource句柄并返回;
上面2,3,5方式其实都是将路径认为是classpath资源并返回相应的句柄,对同一个classpath资源路径,以下三种路径
分别对应上面的2,3,5三种情况 :
2. classpath:test/resources/SpringDefaultResourceLoaderDemo.class
3. /test/resources/SpringDefaultResourceLoaderDemo.class
5. test/resources/SpringDefaultResourceLoaderDemo.class

Spring资源加载器抽象和缺省实现 -- ResourceLoader + DefaultResourceLoader(摘)的更多相关文章

  1. 手撸Spring框架,设计与实现资源加载器,从Spring.xml解析和注册Bean对象

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你写的代码,能接的住产品加需求吗? 接,是能接的,接几次也行,哪怕就一个类一片的 i ...

  2. libgdx学习记录16——资源加载器AssetManager

    AssetManager用于对游戏中的资源进行加载.当游戏中资源(图片.背景音乐等)较大时,加载时会需要较长时间,可能会阻塞渲染线程,使用AssetManager可以解决此类问题. 主要优点: 1. ...

  3. 05.Spring 资源加载 - Resource

    基本概念 Spring 把所有能记录信息的载体,如各种类型的文件.二进制流等都称为资源. 对 Spring 开发者来说,最常用的资源就是 Spring 配置文件(通常是一份 XML 格式的文件). S ...

  4. spring资源加载结构解析

    1.spring中资源加载使用resources的原因? 在java将不同资源抽象成url,然后通过注册不同的hander来处理不同读取逻辑,一般hander使用协议的前缀来命名,如http,jar, ...

  5. 06.Spring 资源加载 - ResourceLoader

    基本概念 ResourceLoader 接口,在 Spring 中用于加载资源,通过它可以获取一个 Resouce 对象. 内部构造 首先来看它的接口定义: public interface Reso ...

  6. Spring资源加载基础ClassLoader

    1 ClassLoader工作机制 1.1 ClassLoader作用 寻找类字节码文件并构造出类在JVM内部表示的组件.负责运行时查找和装入Class字节码文件 1.2 装载步骤 1.2.1 装载 ...

  7. spring 资源加载使用说明

    Spring 提供了一个强大加载资源的机制,不但能够通过“classpath:”.“file:” 等资源地址前缀识别不同的资源类型,还支持Ant 风格带通配符的资源地址. 首先,我们来了解一下Spri ...

  8. Spring 资源加载

    pom.xml ``` org.springframework spring-core 4.3.14.RELEASE org.springframework spring-beans 4.3.16.R ...

  9. 【死磕 Spring】----- IOC 之 Spring 统一资源加载策略

    原文出自:http://cmsblogs.com 在学 Java SE 的时候我们学习了一个标准类 java.net.URL,该类在 Java SE 中的定位为统一资源定位器(Uniform Reso ...

随机推荐

  1. Nginx之 try_files 指令

    location / { try_files $uri $uri/ /index.php; } 当用户请求 http://localhost/example 时,这里的 $uri 就是 /exampl ...

  2. jquery中的globalEval()源码分析

    //20170724 huanhua 定义成全局的变量 // 在谷歌浏览器下运行的: // function fun(){ eval('var a=1'); } 此时 定义的 a 就是局部的变量 // ...

  3. python学习Day13 函数的嵌套定义、global、nonlocal关键字、闭包及闭包的运用场景、装饰器

    复习 1.函数对象:函数名 => 存放的是函数的内存地址1)函数名 - 找到的是函数的内存地址2)函数名() - 调用函数 => 函数的返回值 eg:fn()() => fn的返回值 ...

  4. 交叉熵理解:softmax_cross_entropy,binary_cross_entropy,sigmoid_cross_entropy简介

    cross entropy 交叉熵的概念网上一大堆了,具体问度娘,这里主要介绍深度学习中,使用交叉熵作为类别分类. 1.二元交叉熵 binary_cross_entropy 我们通常见的交叉熵是二元交 ...

  5. java后台动态生成导出excel

    p ublic void export(List<WechatUser> wechatUserList, HttpServletResponse response) throws IOEx ...

  6. 关于STM32CubeMX使用LL库设置PWM输出

    HAL和LL库 HAL是ST为了实现代码在ST家族的MCU上的移植性,推出的一个库,称为硬件抽象层,很明显,这样做将会牺牲存储资源,所以项目最后的代码比较冗余,且运行效率大大降低,运行速度受制于fla ...

  7. 通过代码启动appium服务

    如果选择npm安装的最新版appium 1.8.0以上版本,启动appium的时候,你会发现无法使用Node.js命令 这里给出两种方法来启动appim: 方法一: /** * 使用AppiumSer ...

  8. Python学习笔记5程序的控制结构

    1.分支结构 (1)单分支结构 (2)二分支结构 (3)多分支结构 条件判断 (4)程序的异常处理 2.实例:身体质量指数BMI 思路一(国内,稍作修改就是国际): 思路二: height,weigh ...

  9. 关于.idea未上传导致不能显示项目文件结构的问题

    方法一: 关闭IDEA, 然后删除项目文件夹下的.idea文件夹 重新用IDEA工具打开项目 方法二: 菜单:File -> Invalidate Caches / Restart 方法三: 配 ...

  10. synchronized锁机制 之 代码块锁(转)

    synchronized同步代码块 用关键字synchronized声明方法在某些情况下是有弊端的,比如A线程调用同步方法执行一个较长时间的任务,那么B线程必须等待比较长的时间.这种情况下可以尝试使用 ...