spring源码-资源资源加载器

news2024/12/27 1:46:37

Spring资源抽象Resource

Spring对各种底层资源,比如文件系统中的一个文件,classpath上的一个文件,或者一个网络URL,统一抽象为接口Resource来表示

因为每个底层文件都可以以一个只读InputStream的方式打开,所以Resource接口继承自接口InputStreamSource。InputStreamSource接口中定义了方法getInputStream()用于返回打开该资源所对应的输入流。

 具体有如下7种实现

 

 

package com.sqz.resources;

import org.springframework.core.io.*;

import java.io.FileInputStream;
import java.io.InputStream;

public class ResourceDemo {

	public static void main(String[] args) throws Exception {
		{
			Resource resource = new ClassPathResource("application.xml");
			describe(resource);
		}
		{
			Resource resource = new FileSystemResource("/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java");
			describe(resource);
		}
		{//
			Resource resource = new UrlResource("https://docs.spring.io");
			describe(resource);
		}

		{//
			Resource resource = new ByteArrayResource("Hello".getBytes());
			describe(resource);
		}
		{// test.txt 是当前磁盘卷根目录下一个存在的文件,内容是:Test Spring Resource
			InputStream is = new FileInputStream("/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/life/MyLifeStyleBean.java");
			Resource resource = new InputStreamResource(is);
			describe(resource);
		}

	}

	public static void describe(Resource resource) throws Exception {
		System.out.println("====================================");
		System.out.println("toString : {}"+resource.toString());
		System.out.println("contentLength : {}"+resource.contentLength());
		System.out.println("exists : {}"+resource.exists());
		System.out.println("getDescription : {}"+resource.getDescription());
		System.out.println("isReadable : {}"+resource.isReadable());
		System.out.println("isOpen : {}"+resource.isOpen());
		System.out.println("getFilename : {}"+resource.getFilename());
		System.out.println("isFile : {}"+resource.isFile());
		if (resource.isFile()) {
			// getFile()仅针对文件类型Resource有效,可以是文件系统文件或者classpath上的文件
			System.out.println("getFile : {}"+resource.getFile());
		}

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


}

输出结果

====================================
toString : {}class path resource [application.xml]
contentLength : {}0
exists : {}true
getDescription : {}class path resource [application.xml]
isReadable : {}true
isOpen : {}false
getFilename : {}application.xml
isFile : {}true
getFile : {}/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/build/resources/main/application.xml
lastModified : {}1672723467682
getURI : {}file:/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/build/resources/main/application.xml
getURL : {}file:/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/build/resources/main/application.xml
====================================
toString : {}file [/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java]
contentLength : {}394
exists : {}true
getDescription : {}file [/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java]
isReadable : {}true
isOpen : {}false
getFilename : {}RunApp.java
isFile : {}true
getFile : {}/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java
lastModified : {}1672537275111
getURI : {}file:/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java
getURL : {}file:/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java
====================================
toString : {}URL [https://docs.spring.io]
contentLength : {}-1
exists : {}true
getDescription : {}URL [https://docs.spring.io]
isReadable : {}true
isOpen : {}false
getFilename : {}
isFile : {}false
lastModified : {}0
getURI : {}https://docs.spring.io
getURL : {}https://docs.spring.io
====================================
toString : {}Byte array resource [resource loaded from byte array]
contentLength : {}5
exists : {}true
getDescription : {}Byte array resource [resource loaded from byte array]
isReadable : {}true
isOpen : {}false
getFilename : {}null
isFile : {}false
====================================
toString : {}InputStream resource [resource loaded through InputStream]
contentLength : {}498
exists : {}true
getDescription : {}InputStream resource [resource loaded through InputStream]
isReadable : {}true
isOpen : {}true
getFilename : {}null
isFile : {}false

ResourceLoader

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

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

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

public interface ResourceLoader {

	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();

}

测试ResourceLoader

package com.sqz.resources;

import org.springframework.core.io.*;

public class SpringDefaultResourceLoaderDemo {

	public static void main(String[] args) throws Exception {
		load();
	}

	public static void load() throws Exception {
		ResourceLoader resourceLoader = new DefaultResourceLoader();
		{// 获取 classpath 上的某个资源 : 路径带前缀 classpath:
			Resource resource = resourceLoader.getResource(
					"classpath:application.xml");
			describe(resource);
		}

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

		{// 获取 classpath 上的某个资源 : 路径前缀为/,而不是 classpath:
			Resource resource = resourceLoader.getResource(
					"/application.xml");
			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:/Users/mac/workspace/spring-framework-5.2.0.RELEASE/spring-demo/src/main/java/com/sqz/RunApp.java");
			describe(resource);
		}
	}


	public static void describe(Resource resource) throws Exception {
		System.out.println("====================================");
		System.out.println("toString : {}"+resource.toString());
		System.out.println("contentLength : {}"+resource.contentLength());
		System.out.println("exists : {}"+resource.exists());
		System.out.println("getDescription : {}"+resource.getDescription());
		System.out.println("isReadable : {}"+resource.isReadable());
		System.out.println("isOpen : {}"+resource.isOpen());
		System.out.println("getFilename : {}"+resource.getFilename());
		System.out.println("isFile : {}"+resource.isFile());
		if (resource.isFile()) {
			// getFile()仅针对文件类型Resource有效,可以是文件系统文件或者classpath上的文件
			System.out.println("getFile : {}"+resource.getFile());
		}

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


用户为DefaultResourceLoader提供自定义的ProtocolResolver用来识别特定格式的资源路径

使用方法DefaultResourceLoader#addProtocolResolver添加ProtocolResolver,可以提供多个,也可以不提供。

缺省情况下,DefaultResourceLoader不包含ProtocolResolver。

给定一个路径,调用方法DefaultResourceLoader#getResource获取资源对象(也可以叫做句柄)

1 轮询每个ProtocolResolver看它们哪个可以处理该路径,如果可以让其处理并返回相应的资源句柄;

2 如果路径以"/"开头,尝试将其处理为一个ClassPathContextResource句柄并返回;

3 如果路径以"classpath:“前缀开头,去除路径中前缀部分之后将其封装成一个ClassPathResource句柄并返回;

4 如果路径是URL格式

5 如果路径以"file:”/“vfs:”/"vfsfile:"前缀开头,将其封装成一个FileUrlResource句柄并返回;

6 否则将其封装成一个UrlResource句柄返回;

7 其他格式,仍然尝试将其封装一个ClassPathContextResource句柄并返回;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/138149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ModuleNotFoundError: No module named ‘cs231n‘

在colab上完成cs231n的作业时发现,报了No module named cs231n’这个错误,查询后也没有找到合适的答案 仔细检查,发现是没有找到assignment1下的cs231n文件夹,然后去网站核对视频教程,发现没有搞错,视频中…

浮点数的储存

浮点数的储存一.浮点数的三段式(S,E,M)1.如何放入2.如何取出二.为什么浮点数不能直接比较三.解释第一个问题我们都知道整形在内存中是按照补码的形式储存的,但是浮点数的储存却和整数的截然不同,浮点数没有所谓是原反补并且浮点数…

SSM框架学习记录-MyBatisPlus_day01

1.入门案例与简介 MybatisPlus是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提供效率 未使用MybatisPlus时,在dao接口中的代码如下: Mapper public interface UserDao {Select("select * from user where id#{id}")publ…

冬日宅家选哪款投影仪比较好?极米H5陪你温暖过冬天

随着室外温度的逐步下降,寒冬也真的来了。相信对于许多朋友来说,宅家是冬季最惬意的时光,就是开着空调、电暖风、暖气,在温暖的室内,再打开投影仪,用超大屏追剧、看看电影,听听美妙的音乐&#…

光伏二次设备概述

概述 分布式光伏发电项目一般根据并网的电压等级分为380V和10KV。一般电压等级为380V低压并并网基本不涉及到什么二次产品,通常采用光伏并网柜就能解决,常见的并网设备为防孤岛保护装置和电能质量在线监测装置为主。而10KV并网的光伏容量一般处于1MWP到1…

加强企业数据库安全的行为准则

现在大多数企业都拥有可靠的网络安全程序,这些程序利用多种控件来实现深度防御安全性。通过这些程序,企业服务器得到加固,企业端点得到保护,监控工具也得以部署。还能够消除来自端点设备的高度敏感信息,并整合企业系统…

基于jsp+sevlet+mysql实验室设备管理系统

基于jspsevletmysql实验室设备管理系统一、系统介绍二、功能展示1.通知公告(学生)2.实验设备借用申请(学生)3.设备借用记录(学生)4.实验室预约申请(老师)5.实验室预约记录(老师)6.实验设备借用申请(老师)7.设备借用记录(老师)8.通知公告(管理员)9.实验室管理(管理员)10.设备管理…

QA | 关于可编程信号发生器,您在使用中可能遇到的问题

Q1:为什么信号源插在电脑上会显示电压不足? A:通常需要比普通电脑USB接口能提供更大的功率,需要高达2.0A的电流,超出了许多老式 USB 端口的水平。可以通过多种方式满足这一要求。适配器、USB 3.0计算机/笔记本电脑端口…

python——Matplotlib之fill_between函数

Matplotlib是Python提供的一套基于NumPy的绘图工具包,用Python实现与MATLAB相似的命令API,十分适合交互式绘制图表,成为Python中应用非常广的绘图工具包之一。 在对数据可视化时,为了突出某一段数据需要对部分区域进行填充处理。…

用这4招优雅的实现Spring Boot 异步线程间数据传递

Spring Boot 自定义线程池实现异步开发相信看过文章都了解,但是在实际开发中需要在父子线程之间传递一些数据,比如用户信息,链路信息等等 比如用户登录信息使用ThreadLocal存放保证线程隔离,代码如下: /*** author 公…

认监委调整《有机产品认证目录》

认监委关于调整《有机产品认证目录》的公告为进一步完善有机产品认证制度,规范有机产品认证活动,促进有机产业发展,根据《有机产品认证管理办法》(质检总局令第155号)和《有机产品认证实施规则》(认监委201…

大数据编程期末大作业

大数据编程期末大作业 文章目录大数据编程期末大作业一、Hadoop基础操作二、RDD编程三、SparkSQL编程四、SparkStreaming编程一、Hadoop基础操作 在HDFS中创建目录 /user/root/你的名字 例如李四同学 /user/root/lisi 首先我们需要启动hdfs,我们直接在终端输入如下命…

JavaScript for 循环

文章目录JavaScript for 循环JavaScript 循环使用for循环不同类型的循环For 循环语句 1语句 2语句 3For/In 循环JavaScript for 循环 循环可以将代码块执行指定的次数。 JavaScript 循环 如果您希望一遍又一遍地运行相同的代码,并且每次的值都不同,那么…

MCU-51:单片机DS18B20温度报警器

目录一、DS18B201.1 DS18B20介绍1.2 引脚及应用电路1.3 内部结构框图1.4 存储器结构二、单总线2.1 单总线介绍2.2 单总线电路规范2.3 单总线时序结构三、DS18B20操作流程四、DS18B20数据帧五、温度存储格式六、代码演示6.1 温度读取6.2 温度报警器注意:一定要看一、…

Qt OpenGL(04)Sierpinski 镂垫 3D 版

文章目录三维 Siepinski 镂垫相关代码main.cppHelp.hppWidget.hWidget.cpp顶点着色器片元着色器总结三维 Siepinski 镂垫 把前面的二维Sierpinski程序转换成一个生成三维Sierpinski镂垫的程序,也就是说要绘制的镂垫不再只是限制在一个平面里。我们可仿效对二维镂垫所…

什么? @ConditionalOnMissingBean 你没设置value?

序 这两天再看 公司 之前写的组件的代码,不看不知道,一看吓一跳。。。。这里就说其中一个 不知道你在写组件中的 Bean 加载的时候 怎么写? 方法一 直接META-INF/spring.factories 写 org.springframework.boot.autoconfigure.EnableAuto…

消息队列应用与原理剖析

什么是消息队列 消息队列:在消息的传输过程中保存消息的容器,生产者和消费者不直接通讯,依靠队列保证消息的可靠性,避免了系统间的相互影响。系统间的数据流通道 应用场景 异步处理:用户注册后,需要发注…

linux C--管道

这里写自定义目录标题基本概念管道特征编写模型有名管道模型示例demowrite.cread.c结果记录笔记1无名管道基本概念 进程间存在天然的壁垒,进程间通信(Interperocess Communication,IPC)是指二个或者多个进程之间进行数据交换的过程 管道特征 管道是进程间通讯的一种常用方法…

Tomcat安装及使用

1.下载 Tomcat官网 选择系统 2.解压 解压到没有中文路径的文件夹中,解压路径会在配置环境变量时用到 3.配置环境变量 在电脑点击鼠标右键->点击属性>点击高级系统设置->点击环境变量->新建系统变量 1.新建系统变量 变量名为CATALINA_HOME,变…

【unity3D】DoTween动画插件(下)

💗 未来的游戏开发程序媛,现在的努力学习菜鸡 💦本专栏是我关于游戏开发的学习笔记 🈶本篇是unity的DoTween动画插件可视化编辑 DoTween动画插件(可视化编辑)DOTween AnimationDoTween Path路径编辑器Scene…