Resource接口和实现类

Resource接口

JDK提供的访问资源的类(如java.NET.URL,File)等并不能很好很方便的满足各种底层资源的访问需求。Spring设计了一个Resource接口,为应用提供了更强的访问底层资源的能力,该接口拥有对应不同资源类型的实现类。

Spring的Resource接口位于org.sprigframework.core.io中。旨在实现一个更強大的接口,用于抽象对低级资源的方向。以下演示了Resource接口定义的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
/**
* 用于描述资源的接口,该接口抽象了底层资源的实际类型,如文件或类路径资源。
*
* <p>对于每个资源,如果它在物理形式上存在,都可以打开一个输入流,但只有某些资源才能返回 URL 或文件句柄。具体行为取决于其实现。
*/
public interface Resource extends InputStreamSource {

/**
* 判断此资源是否在物理形式上真正存在。
*/
boolean exists();

/**
* 指示是否可以通过 {@link #getInputStream()} 读取此资源的非空内容。
* 实际的内容读取可能仍然失败。
*/
default boolean isReadable() {
return exists();
}

/**
* 指示此资源是否代表一个打开的流的句柄。
* 如果为 true,则输入流不能被多次读取,并且在读取后必须被关闭,以避免资源泄露。
*/
default boolean isOpen() {
return false;
}

/**
* 判断此资源是否代表文件系统中的文件。
*/
default boolean isFile() {
return false;
}

/**
* 返回此资源的 URL 句柄。
*/
URL getURL() throws IOException;

/**
* 返回此资源的 URI 句柄。
*/
URI getURI() throws IOException;

/**
* 返回此资源的文件句柄。
*/
File getFile() throws IOException;

/**
* 返回一个 {@link ReadableByteChannel}。
*/
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}

/**
* 确定此资源的内容长度。
*/
long contentLength() throws IOException;

/**
* 确定此资源的最后修改时间戳。
*/
long lastModified() throws IOException;

/**
* 创建相对于此资源的资源。
*/
Resource createRelative(String relativePath) throws IOException;

/**
* 返回此资源的文件名。
*/
@Nullable
String getFilename();

/**
* 返回此资源的描述,用于在处理资源时的错误输出。
*/
String getDescription();
}

Resource接口継承了InputStreamSource接口,提供了很多InputStreamSource所没有的方法。

InputStreamSource接口,只有一个方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 表示可以提供输入流的资源或对象的接口。
*/
public interface InputStreamSource {
/**
* 返回基础资源内容的 InputStream。
* 期望每次调用都会创建一个新的流。
* @return 基础资源的输入流(不能为 null)
* @throws java.io.FileNotFoundException 如果基础资源不存在
* @throws IOException 如果无法打开内容流
*/
InputStream getInputStream() throws IOException;
}

Resource的实现类

Resource接口是Spring资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成,每个实现类代表-一种资源访问策略。Resource-一般包括这些实现类: UrlResource,ClassPathResource,FilsSystemResource,ServletContextResource,InputStreamResource,ByteArrayResource

UrlResource

用于访问通过 URL 表示的资源,比如 http:// 开头的网络资源(如网页、远程文件等),也可以是 file:// 开头的本地文件资源。它会根据 URL 的协议来决定如何获取资源。例如,当你需要访问一个远程服务器上的文件时,就可以使用 UrlResource。代码示例如下

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.core.io.UrlResource;
import java.net.URL;

public class UrlResourceExample {
public static void main(String[] args) throws Exception {
URL url = new URL("http://example.com/somefile.txt");
UrlResource resource = new UrlResource(url);
// 这里可以进行资源的读取等操作,比如获取输入流
java.io.InputStream inputStream = resource.getInputStream();
// 处理输入流
inputStream.close();
}
}

ClassPathResource

用于访问类路径下的资源文件。在 Java 项目中,类路径通常包含 src/main/resources(在 Maven 或 Gradle 项目结构中)这样的目录。它会从类加载器的类路径中查找资源。例如,如果你有一个配置文件 application.properties 放在 src/main/resources 目录下,你可以通过 ClassPathResource 来获取它。示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package edu.software.ergoutree.springresources;

import org.springframework.core.io.ClassPathResource;

import java.io.IOException;
import java.io.InputStream;

// 访问类路径下的资源
public class ClassPathDemo {
public static void main(String[] args) {
loadClassPathResources("test");
}

public static void loadClassPathResources(String path){
// 创建对象 ClassPathResource
ClassPathResource resource = new ClassPathResource(path);

System.out.println(resource.getFilename());
System.out.println(resource.getDescription());
try {
InputStream in = resource.getInputStream();
byte[] bytes = new byte[in.available()];
while (in.read(bytes) != -1){
System.out.println(new String(bytes));
}
} catch (IOException e) {
throw new RuntimeException(e);
}

}
}

FileSystemResource

用于访问本地文件系统中的资源。它通过文件路径来定位资源,不管是绝对路径还是相对路径(相对于当前工作目录)。比如你要访问本地磁盘上的一个文件,就可以使用 FileSystemResource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package edu.software.ergoutree.springresources;

import org.springframework.core.io.FileSystemResource;

import java.io.IOException;
import java.io.InputStream;

// 访问系统资源
public class FileSystemResourceDemo {
public static void loadFileResource(String fileName) {
// 创建对象
FileSystemResource resource = new FileSystemResource(fileName);
System.out.println(resource.getFilename());
System.out.println(resource.getDescription());

try {
InputStream in = resource.getInputStream();
byte[] bytes = new byte[in.available()];
while (in.read(bytes) != -1){
System.out.println(new String(bytes));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}

public static void main(String[] args) {
loadFileResource("Spring Framework\\Spring6Exp\\spring-resources\\src\\main\\resources\\test");
}
}

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
    23
    import org.springframework.web.context.ServletContextAware;
    import org.springframework.web.context.support.ServletContextResource;
    import javax.servlet.ServletContext;

    public class ServletContextResourceExample implements ServletContextAware {
    private ServletContext servletContext;

    @Override
    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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.core.io.InputStreamResource;
import java.io.ByteArrayInputStream;
import java.io.IOException;

public class InputStreamResourceExample {
public static void main(String[] args) throws IOException {
String data = "Some sample data";
ByteArrayInputStream inputStream = new ByteArrayInputStream(data.getBytes());
InputStreamResource resource = new InputStreamResource(inputStream);
// 这里可以对 resource 进行操作,比如获取输入流
java.io.InputStream actualInputStream = resource.getInputStream();
// 处理输入流
actualInputStream.close();
}
}

ByteArrayResource

用于将字节数组包装成 Resource 对象。它适用于将内存中的字节数据当作一种资源来处理。例如,如果你在程序中生成了一些字节数据,然后想要以 Resource 的形式使用它,就可以使用 ByteArrayResource。示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.core.io.ByteArrayResource;
import java.io.IOException;

public class ByteArrayResourceExample {
public static void main(String[] args) throws IOException {
byte[] byteArray = "Hello, World!".getBytes();
ByteArrayResource resource = new ByteArrayResource(byteArray);
// 可以获取输入流来读取字节数组内容
java.io.InputStream inputStream = resource.getInputStream();
// 处理输入流
inputStream.close();
}
}

这些 Resource 接口的实现类,为在 Spring 应用中访问不同类型的资源提供了方便和统一的方式,使得开发者可以根据具体的资源来源选择合适的实现类来进行资源操作。


ResourceLoader接口

Spring提供了如下两个标志性接口

ResourceLoader:该接口的实现类实例可以获得一个Resource实例

ResourceLoaderAware:该接口的实现类实例可以获得一个ResourceLoader的引用

org.springframework.core.io.ResourceLoader 是 Spring 框架中的一个关键接口,它定义了如何获取资源(例如类路径资源、文件系统资源或网页资源)的策略。这个接口是 Spring 资源加载抽象的核心,使得应用程序可以从不同的资源位置以统一的方式加载资源。

Spring将采用和ApplicationContext相同的策略来访问资源。也就是说,如果ApplicationContextFileSystemXmlApplicationContext, res 就是FileSystemResource实例;如果ApplicationContextClassPathXmIApplicationContext, res 就是ClassPathResource实例

当Spring应用需要进行资源访问时,实际上并不需要直接使用 Resource 实现类,而是调用 ResourceLoader 实例的 getResource()方法来获得资源,ReosurceLoader将会负责选择Reosurce实现类,也就是确定具体的资源访问策 略,从而将应用程序和具体的资源访问策略分离开来

另外,使用ApplicationContext访问资源时,可通过不同前缀指定强制使用指定的ClassPathResource、 FileSystemResource等实现类.(多态)

1
2
3
Resource res = ctx.getResource("classpath:bean.xml");
Resource res = ctx.getResource("file:bean.xml");
Resource res = ctx.getResource("https://localhost8080.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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
* 用于加载资源(例如类路径或文件系统资源)的策略接口。
* 一个 ApplicationContext 需要提供此功能以及扩展的 ResourcePatternResolver 支持。
*
* DefaultResourceLoader 是一个独立的实现,可在 ApplicationContext 外部使用,并被 ResourceEditor 使用。
*
* 当在 ApplicationContext 中运行时,类型为 Resource 和 Resource[] 的 Bean 属性可以从字符串中填充,使用特定上下文的资源加载策略。
*
* @author Juergen Hoeller
* @since 10.03.2004
*/
public interface ResourceLoader {

/** 用于从类路径加载的伪 URL 前缀:"classpath:"。 */
String CLASSPATH_URL_PREFIX = ResourceUtils.CLASSPATH_URL_PREFIX;

/**
* 返回指定资源位置的 Resource 句柄。
* 该句柄应始终是一个可重用的资源描述符,允许进行多次 Resource#getInputStream() 调用。
* 必须支持完全限定的 URLs,例如 "file:C:/test.dat"。
* 必须支持类路径伪-URLs,例如 "classpath:test.dat"。
* 应支持相对文件路径,例如 "WEB-INF/test.dat"。
* (这将是实现特定的,通常由 ApplicationContext 实现提供。)
* 请注意,Resource 句柄并不意味着资源存在;我们需要调用 Resource#exists 来检查其存在性。
*
* @param location 资源位置
*/
Resource getResource(String location);

/**
* 公开此 ResourceLoader 使用的 ClassLoader。
* 需要直接访问 ClassLoader 的客户端可以与 ResourceLoader 以统一的方式这样做,而不是依赖线程上下文 ClassLoader。
*
* @return ClassLoader(仅当连系统 ClassLoader 都不可访问时为 null)
*/
@Nullable
ClassLoader getClassLoader();
}
1
2
3
4
5
6
7
8
9
10
public class ResourceLoaderDemo {

public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext();
Resource resource = context.getResource("test");

ApplicationContext ctx = new FileSystemXmlApplicationContext();
Resource resource2 = context.getResource("test");
}
}

主要实现

  1. 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
    23
    public 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/ 下。

与其他组件的关系

  1. ApplicationContext

    所有的 Spring ApplicationContext 都实现了 ResourceLoader。这意味着我们可以使用 Spring 上下文本身来加载资源。

  2. Resource

    ResourceLoader 返回 Resource 对象,它代表实际的资源,可以是文件系统中的文件、类路径资源、URLs 等。Resource 提供了访问和读取资源内容的方法。

  3. ResourcePatternResolver 这是 ResourceLoader 的扩展,可以解析给定的位置模式以加载多个资源。PathMatchingResourcePatternResolver 是它的主要实现。

  4. ResourceEditor 这是一个属性编辑器,用于将字符串转换为 Resource 对象。它内部使用 ResourceLoader 来执行转换。

  5. ResourceLoaderAware

    这是一个特殊的接口,任何 bean 如果实现了它,那么它就可以在被创建时获得对 ResourceLoader 的引用,这样它就可以自己加载资源。

  6. EmbeddedValueResolverAware

    一些组件,如属性占位符处理器,可能需要解析值中的动态部分。它们可以使用 ResourceLoader 作为解析这些值的一部分,特别是当值代表资源位置时。

  7. 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 作为参数传递进去。

源码

img

ResourceLoaderAware 主要用于获取加载当前 Bean 的 ResourceLoader,使得 Bean 能够在运行时获取到关于资源加载的能力。

使用

要让一个Bean实现 ResourceLoaderAware 接口,需要按以下步骤进行

img
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package org.example.cheney;

import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.InputStream;

public class DemoBean implements ResourceLoaderAware {
private ResourceLoader resourceLoader;

@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
System.out.println("【ResourceLoaderAware】: 通过 ResourceLoader 创建 Bean");
}

public void loadResource(String resourceName) throws Exception {
// 使用 ResourceLoader 加载资源
System.out.println("加载的文件名是: " + resourceName);
Resource resource = resourceLoader.getResource(resourceName);
InputStream inputStream = resource.getInputStream();
// 读取资源内容
byte[] contentBytes = new byte[inputStream.available()];
inputStream.read(contentBytes);
String content = new String(contentBytes);
System.out.println("文件内容:\n" + content);
}
}

配置bean

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
>
<bean id="demoBean" class="org.example.cheney.DemoBean"/>
</beans>

测试输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package org.example.cheney;

import org.springframework.context.support.AbstractXmlApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
public static void main(String[] args) throws Exception {
String location = "applicationContext.xml";
try (AbstractXmlApplicationContext context = new ClassPathXmlApplicationContext(location)) {
DemoBean demo = (DemoBean) context.getBean("demoBean");
demo.loadResource("classpath:demo.txt");
System.out.println("End.");
}
}
}

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
2
3
4
5
6
7
8
9
10
11
12
13
package edu.software.ergoutree.springresources.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
RescoureBean rescoureBean = context.getBean(RescoureBean.class);
rescoureBean.pares();
}
}

bean配置

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--解耦合-->
<bean id="rescoureBean" class="edu.software.ergoutree.springresources.di.RescoureBean">
<property name="resource" value="classpath*:test"></property>
</bean>
</beans>

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
package edu.software.ergoutree.springresources.di;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBean {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
RescoureBean rescoureBean = context.getBean(RescoureBean.class);
rescoureBean.pares();
}
}


应用程序上下文和资源路径–Resource 指定访问策略

在 Spring 框架中,应用程序上下文(ApplicationContext)不仅负责管理 Bean 的生命周期,还提供了资源加载的能力。通过 ApplicationContext,开发者可以方便地访问不同类型的资源,而无需关心底层的资源访问细节。ApplicationContext 本身实现了 ResourceLoader 接口,因此可以直接通过上下文加载资源。

资源路径的指定方式

Spring 支持多种资源路径的指定方式,开发者可以通过不同的前缀来强制使用特定的资源访问策略。以下是常见的资源路径前缀及其对应的访问策略:

  1. classpath: 表示从类路径下加载资源。例如:

    1
    Resource resource = context.getResource("classpath:config.properties");

    这会从类路径(如 src/main/resources)中查找 config.properties 文件。

  2. file: 表示从文件系统中加载资源。例如:

    1
    Resource resource = context.getResource("file:/path/to/config.properties");

    这会从文件系统的指定路径加载文件。

  3. http:https: 表示从网络 URL 加载资源。例如:

    1
    Resource resource = context.getResource("https://example.com/config.properties");

    这会通过 HTTP 或 HTTPS 协议从远程服务器加载资源。

  4. 无前缀 如果没有指定前缀,ApplicationContext 会根据上下文类型决定默认的资源访问策略:

    • 对于 ClassPathXmlApplicationContext,默认从类路径加载资源。
    • 对于 FileSystemXmlApplicationContext,默认从文件系统加载资源。

示例代码

以下是一个完整的示例,展示如何通过 ApplicationContext 加载不同类型的资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;

public class ResourceLoadingDemo {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext();

// 从类路径加载资源
Resource classpathResource = context.getResource("classpath:application.properties");
printResourceContent(classpathResource);

// 从文件系统加载资源
Resource fileResource = context.getResource("file:/path/to/myfile.txt");
printResourceContent(fileResource);

// 从网络 URL 加载资源
Resource urlResource = context.getResource("https://example.com/data.json");
printResourceContent(urlResource);
}

private static void printResourceContent(Resource resource) {
try (InputStream inputStream = resource.getInputStream()) {
byte[] bytes = inputStream.readAllBytes();
System.out.println("Resource content: " + new String(bytes));
} catch (IOException e) {
System.err.println("Failed to read resource: " + e.getMessage());
}
}
}

资源路径的通配符支持

Spring 还支持使用通配符加载多个资源,例如:

  • classpath*::从所有类路径下匹配的资源加载。加载多个
  • file:classpath: 结合通配符:匹配符合模式的文件。
1
2
3
4
Resource[] resources = context.getResources("classpath*:config/*.properties");
for (Resource res : resources) {
System.out.println("Found resource: " + res.getFilename());
}

通过 ApplicationContext 加载资源时,开发者可以通过前缀指定资源的访问策略,从而实现灵活的资源管理。这种方式不仅简化了代码,还提高了应用程序的可维护性和可扩展性。无论是类路径资源、文件系统资源还是网络资源,Spring 都提供了统一的访问接口,使得资源加载变得简单而高效。