Resource接口和实现类
Resource接口
JDK提供的访问资源的类(如java.NET.URL,File)等并不能很好很方便的满足各种底层资源的访问需求。Spring设计了一个Resource接口,为应用提供了更强的访问底层资源的能力,该接口拥有对应不同资源类型的实现类。
Spring的Resource接口位于org.sprigframework.core.io中。旨在实现一个更強大的接口,用于抽象对低级资源的方向。以下演示了Resource接口定义的方法
1 | /** |
Resource接口継承了InputStreamSource接口,提供了很多InputStreamSource所没有的方法。
InputStreamSource接口,只有一个方法:
1 | /** |
Resource的实现类
Resource接口是Spring资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成,每个实现类代表-一种资源访问策略。Resource-一般包括这些实现类: UrlResource,ClassPathResource,FilsSystemResource,ServletContextResource,InputStreamResource,ByteArrayResource
UrlResource
用于访问通过 URL
表示的资源,比如 http://
开头的网络资源(如网页、远程文件等),也可以是 file://
开头的本地文件资源。它会根据 URL
的协议来决定如何获取资源。例如,当你需要访问一个远程服务器上的文件时,就可以使用
UrlResource
。代码示例如下
1 | import org.springframework.core.io.UrlResource; |
ClassPathResource
用于访问类路径下的资源文件。在 Java 项目中,类路径通常包含
src/main/resources
(在 Maven 或 Gradle
项目结构中)这样的目录。它会从类加载器的类路径中查找资源。例如,如果你有一个配置文件
application.properties
放在 src/main/resources
目录下,你可以通过 ClassPathResource
来获取它。示例代码:
1 | package edu.software.ergoutree.springresources; |
FileSystemResource
用于访问本地文件系统中的资源。它通过文件路径来定位资源,不管是绝对路径还是相对路径(相对于当前工作目录)。比如你要访问本地磁盘上的一个文件,就可以使用
FileSystemResource
。
1 | package edu.software.ergoutree.springresources; |
ServletContextResource
主要用于在 Web 应用(基于 Servlet 的应用)中访问
ServletContext
相关的资源。它根据ServletContext
来解析资源路径,通常用于访问 Web 应用根目录下的资源,比如WEB-INF
目录下的文件。在 Spring Web 应用中使用较多。例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23import org.springframework.web.context.ServletContextAware;
import org.springframework.web.context.support.ServletContextResource;
import javax.servlet.ServletContext;
public class ServletContextResourceExample implements ServletContextAware {
private ServletContext servletContext;
public void setServletContext(ServletContext servletContext) {
this.servletContext = servletContext;
}
public void accessResource() {
ServletContextResource resource = new ServletContextResource(servletContext, "/WEB-INF/somefile.txt");
try {
java.io.InputStream inputStream = resource.getInputStream();
// 处理输入流
inputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
InputStreamResource
允许你将一个已有的 InputStream
包装成
Resource
对象。当你已经通过其他方式获取到了一个输入流,但是又想将其作为
Resource
来使用时,就可以使用这个类。比如从数据库中读取二进制数据得到了一个
InputStream
,然后可以将其包装为
InputStreamResource
。示例:
1 | import org.springframework.core.io.InputStreamResource; |
ByteArrayResource
用于将字节数组包装成 Resource
对象。它适用于将内存中的字节数据当作一种资源来处理。例如,如果你在程序中生成了一些字节数据,然后想要以
Resource
的形式使用它,就可以使用
ByteArrayResource
。示例代码:
1 | import org.springframework.core.io.ByteArrayResource; |
这些 Resource
接口的实现类,为在 Spring
应用中访问不同类型的资源提供了方便和统一的方式,使得开发者可以根据具体的资源来源选择合适的实现类来进行资源操作。
ResourceLoader接口
Spring提供了如下两个标志性接口
ResourceLoader
:该接口的实现类实例可以获得一个Resource实例
ResourceLoaderAware
:该接口的实现类实例可以获得一个ResourceLoader的引用
org.springframework.core.io.ResourceLoader 是 Spring 框架中的一个关键接口,它定义了如何获取资源(例如类路径资源、文件系统资源或网页资源)的策略。这个接口是 Spring 资源加载抽象的核心,使得应用程序可以从不同的资源位置以统一的方式加载资源。
Spring将采用和ApplicationContext
相同的策略来访问资源。也就是说,如果ApplicationContext
是
FileSystemXmlApplicationContext
, res
就是FileSystemResource
实例;如果ApplicationContext
是
ClassPathXmIApplicationContext
, res
就是ClassPathResource
实例
当Spring应用需要进行资源访问时,实际上并不需要直接使用 Resource
实现类,而是调用 ResourceLoader 实例的
getResource()
方法来获得资源,ReosurceLoader
将会负责选择Reosurce
实现类,也就是确定具体的资源访问策
略,从而将应用程序和具体的资源访问策略分离开来
另外,使用ApplicationContext
访问资源时,可通过不同前缀指定强制使用指定的ClassPathResource、
FileSystemResource等实现类.(多态)
1 | Resource res = ctx.getResource("classpath:bean.xml"); |
主要功能
统一资源加载 ResourceLoader 提供了一个标准化的方法来加载资源,不论资源是存放在类路径、文件系统、网络URL还是其他位置。
资源位置解析 根据提供的资源字符串位置(如 “classpath:”, “file:”, “http:”),ResourceLoader 可以确定资源的类型,并为其创建相应的 Resource 实例。
返回 Resource 实例 通过 Resource getResource(String location) 方法,ResourceLoader 返回一个 Resource 对象,代表了指定位置的资源。这使得读取和操作资源变得简单且统一。
与 ClassLoader 的交互 ResourceLoader 通过 ClassLoader getClassLoader() 方法返回与其关联的 ClassLoader。这使得资源加载策略可以与特定的类加载器关联。
扩展性 ResourceLoader 是一个接口,这意味着我们可以实现自己的资源加载策略,或者扩展默认的策略以满足特定需求。
内置实现与整合
Spring 提供了默认的 ResourceLoader 实现,如 DefaultResourceLoader。但更重要的是,org.springframework.context.ApplicationContext 也实现了 ResourceLoader,这意味着 Spring 上下文本身就是一个资源加载器。
接口源码
ResourceLoader 接口为 Spring 框架定义了资源加载策略。它提供了获取资源的方法,并公开了其使用的 ClassLoader。通过这种策略,资源可以从各种来源(如类路径、文件系统等)以统一方式加载。这提供了资源加载的灵活性和一致性,并支持各种资源描述符,如 URL、类路径等。此外,它还允许对资源句柄进行多次重新使用和读取。
1 | /** |
1 | public class ResourceLoaderDemo { |
主要实现
DefaultResourceLoader
- 这是基本的资源加载器实现。它可以处理 “classpath:” 前缀的资源,如果没有提供这样的前缀,它会尝试使用类加载器或文件系统来加载资源。
使用
DefaultResourceLoader
从不同的资源(类路径和文件系统)加载内容。示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class DefaultResourceLoaderDemo {
public static void main(String[] args) {
DefaultResourceLoader loader = new DefaultResourceLoader();
// 从类路径加载资源
Resource classpathResource = loader.getResource("classpath:application.properties");
try (InputStream is = classpathResource.getInputStream()) {
// 读取和处理资源内容
System.out.println("Classpath = "+ new String(is.readAllBytes()));
} catch (IOException e) {
e.printStackTrace();
}
// 加载文件系统中的资源
Resource fileResource = loader.getResource("file:/idea-work-space-xcs/spring-reading/spring-resources/spring-resource-resourceLoader/myfile1.txt");
try (InputStream is = fileResource.getInputStream()) {
// 读取和处理资源内容
System.out.println("File = "+ new String(is.readAllBytes()));
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果发现
从类路径上,我们加载了一个文件:application.properties
。这意味着在我们的项目的类路径中,有这个文件。
从文件系统上,我们加载了一个文件:myfile1.txt。这些文件位于我们之前在代码中硬编码的文件路径
/idea-work-space-xcs/spring-reading/spring-resources/spring-resource-resourceLoader/
下。
与其他组件的关系
ApplicationContext
所有的 Spring ApplicationContext 都实现了 ResourceLoader。这意味着我们可以使用 Spring 上下文本身来加载资源。
Resource
ResourceLoader 返回 Resource 对象,它代表实际的资源,可以是文件系统中的文件、类路径资源、URLs 等。Resource 提供了访问和读取资源内容的方法。
ResourcePatternResolver 这是 ResourceLoader 的扩展,可以解析给定的位置模式以加载多个资源。PathMatchingResourcePatternResolver 是它的主要实现。
ResourceEditor 这是一个属性编辑器,用于将字符串转换为 Resource 对象。它内部使用 ResourceLoader 来执行转换。
ResourceLoaderAware
这是一个特殊的接口,任何 bean 如果实现了它,那么它就可以在被创建时获得对 ResourceLoader 的引用,这样它就可以自己加载资源。
EmbeddedValueResolverAware
一些组件,如属性占位符处理器,可能需要解析值中的动态部分。它们可以使用 ResourceLoader 作为解析这些值的一部分,特别是当值代表资源位置时。
PathMatchingResourcePatternResolver
它是 ResourcePatternResolver 的一个实现,它扩展了 ResourceLoader 来处理以 “classpath*:” 开头的资源模式,这允许加载所有匹配的资源,而不仅仅是第一个找到的资源。
常见问题
加载类路径资源 使用前缀 “classpath:”,例如:loader.getResource(“classpath:myconfig.xml”)。
加载文件系统资源
使用前缀 “file:”,例如:loader.getResource(“file:/path/to/myconfig.xml”)。
加载URL资源
直接使用 URL,例如:loader.getResource(“http://www.example.com/config.xml”)。
资源不存在 使用
Resource.exists()
方法检查资源是否存在。确保路径或位置正确,并且资源真的存在于预期的位置。如何读取资源内容 从 Resource 对象中获取 InputStream,例如:resource.getInputStream()。
从 Resource 获取到文件路径 使用 Resource.getFile()。但请注意,这并不总是有效的,例如当资源实际上是一个类路径资源或URL资源时。
自动注入 ResourceLoader 实现 ResourceLoaderAware 接口,Spring 将自动为我们的 bean 提供 ResourceLoader 的引用。
扩展或自定义资源加载机制 我们可以实现自己的 ResourceLoader 或继承现有的实现,如 DefaultResourceLoader
加载资源时考虑环境或属性占位符 使用 PropertyPlaceholderConfigurer 或 PropertySourcesPlaceholderConfigurer 与 @Value 注解可以解析属性值中的资源路径
ResourceLoaderAware 接口
在 Spring 中,ResourceLoaderAware 接口是一个回调接口,它提供了一个用于设置 Bean 所在的ResourceLoader 的方法。当一个 Bean 实现了 ResourceLoaderAware 接口时,在该 Bean 实例被实例化后,Spring 容器会调用 setResourceLoader 方法,并将该 Bean 所在的 ResourceLoader 作为参数传递进去。
源码

ResourceLoaderAware
主要用于获取加载当前 Bean 的
ResourceLoader
,使得 Bean
能够在运行时获取到关于资源加载的能力。
使用
要让一个Bean实现 ResourceLoaderAware
接口,需要按以下步骤进行

1 | package org.example.cheney; |
配置bean
1 | <?xml version="1.0" encoding="UTF-8"?> |
测试输出
1 | package org.example.cheney; |
ResourceLoaderAware 接口通常用于以下场景:
加载资源:
当一个 Bean 需要在运行时加载外部资源时,可以使用 ResourceLoaderAware 获取 ResourceLoader 并使用它加载资源处理资源相关逻辑: 当一个 Bean 与资源相关的操作时,例如读取配置文件、加载模板文件等,可以使用 ResourceLoaderAware 获取 ResourceLoader
使用Resource作为属性
前面介绍了Spring提供的资源访问策略,但这些依赖访问策略要么需要使用Resource实现类,要么需要使用 ApplicationContext来获取资源。实际上,当应用程序中的Bean实例需要访问资源时,Spring有更好的解决方 法:直接利用依赖注入。从这个意义上来看,Spring框架不仅充分利用了策略模式来简化资源访问,而且还将策 略模式和IoC进行充分地结合,最大程度地简化了Spring资源访问。 归纳起来,如果Bean实例需要访问资源,有如下两种解决方案:
代码中获取Resource实例。
使用依赖注入
对于第一种方式,当程序获取Resource实例时,总需要提供Resource所在的位置,不管通过FileSystemResource创建实例,还是通过ClassPathResource创建实例,或者通过ApplicationContext的getResource()方法获取实例,都需要提供资源位置。这意味着:资源所在的物理位置将被耦合到代码中,如果资源位置发生改变,则必须改写程序。因此,通常建议采用第二种方法,让Spring为Bean实例依赖注入资源。
示例
1 | package edu.software.ergoutree.springresources.di; |
bean配置
1 |
|
测试
1 | package edu.software.ergoutree.springresources.di; |
应用程序上下文和资源路径–Resource 指定访问策略
在 Spring
框架中,应用程序上下文(ApplicationContext
)不仅负责管理
Bean 的生命周期,还提供了资源加载的能力。通过
ApplicationContext
,开发者可以方便地访问不同类型的资源,而无需关心底层的资源访问细节。ApplicationContext
本身实现了 ResourceLoader
接口,因此可以直接通过上下文加载资源。
资源路径的指定方式
Spring 支持多种资源路径的指定方式,开发者可以通过不同的前缀来强制使用特定的资源访问策略。以下是常见的资源路径前缀及其对应的访问策略:
classpath:
表示从类路径下加载资源。例如:1
Resource resource = context.getResource("classpath:config.properties");
这会从类路径(如
src/main/resources
)中查找config.properties
文件。file:
表示从文件系统中加载资源。例如:1
Resource resource = context.getResource("file:/path/to/config.properties");
这会从文件系统的指定路径加载文件。
http:
或https:
表示从网络 URL 加载资源。例如:1
Resource resource = context.getResource("https://example.com/config.properties");
这会通过 HTTP 或 HTTPS 协议从远程服务器加载资源。
无前缀 如果没有指定前缀,
ApplicationContext
会根据上下文类型决定默认的资源访问策略:- 对于
ClassPathXmlApplicationContext
,默认从类路径加载资源。 - 对于
FileSystemXmlApplicationContext
,默认从文件系统加载资源。
- 对于
示例代码
以下是一个完整的示例,展示如何通过 ApplicationContext
加载不同类型的资源:
1 | import org.springframework.context.ApplicationContext; |
资源路径的通配符支持
Spring 还支持使用通配符加载多个资源,例如:
classpath*:
:从所有类路径下匹配的资源加载。加载多个file:
或classpath:
结合通配符:匹配符合模式的文件。
1 | Resource[] resources = context.getResources("classpath*:config/*.properties"); |
通过 ApplicationContext
加载资源时,开发者可以通过前缀指定资源的访问策略,从而实现灵活的资源管理。这种方式不仅简化了代码,还提高了应用程序的可维护性和可扩展性。无论是类路径资源、文件系统资源还是网络资源,Spring
都提供了统一的访问接口,使得资源加载变得简单而高效。