spring-reading./spring-resources/spring-resource-resourceLoader/README.md

235 lines
9.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## ResourceLoader
- [ResourceLoader](#resourceloader)
- [一、基本信息](#一基本信息)
- [二、知识储备](#二知识储备)
- [三、基本描述](#三基本描述)
- [四、主要功能](#四主要功能)
- [五、接口源码](#五接口源码)
- [六、主要实现](#六主要实现)
- [七、最佳实践](#七最佳实践)
- [八、与其他组件的关系](#八与其他组件的关系)
- [九、常见问题](#九常见问题)
### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [掘金](https://juejin.cn/user/4251135018533068/posts) 📚 **源码地址** - [github](https://github.com/xuchengsheng/spring-reading)
### 二、知识储备
1. **Spring 资源抽象**
- [Resource](https://github.com/xuchengsheng/spring-reading/blob/master/spring-resources/spring-resource) 接口及其各种实现。
2. **路径和模式解析**
- Spring 中的路径解析,特别是使用 ant 风格的路径模式,例如 `classpath*:com/example/**/*.xml`
3. **理解不同的资源类型**
- 文件资源、类路径资源、URL 资源、JAR 中的资源等。
### 三、基本描述
`org.springframework.core.io.ResourceLoader` 是 Spring 框架中的一个关键接口,它定义了如何获取资源(例如类路径资源、文件系统资源或网页资源)的策略。这个接口是 Spring 资源加载抽象的核心,使得应用程序可以从不同的资源位置以统一的方式加载资源。
### 四、主要功能
1. **统一资源加载**
- `ResourceLoader` 提供了一个标准化的方法来加载资源不论资源是存放在类路径、文件系统、网络URL还是其他位置。
2. **资源位置解析**
- 根据提供的资源字符串位置(如 "classpath:", "file:", "http:"`ResourceLoader` 可以确定资源的类型,并为其创建相应的 `Resource` 实例。
3. **返回 `Resource` 实例**
- 通过 `Resource getResource(String location)` 方法,`ResourceLoader` 返回一个 `Resource` 对象,代表了指定位置的资源。这使得读取和操作资源变得简单且统一。
4. **`ClassLoader` 的交互**
- `ResourceLoader` 通过 `ClassLoader getClassLoader()` 方法返回与其关联的 `ClassLoader`。这使得资源加载策略可以与特定的类加载器关联。
5. **扩展性**
- `ResourceLoader` 是一个接口,这意味着我们可以实现自己的资源加载策略,或者扩展默认的策略以满足特定需求。
6. **内置实现与整合**
- Spring 提供了默认的 `ResourceLoader` 实现,如 `DefaultResourceLoader`。但更重要的是,`org.springframework.context.ApplicationContext` 也实现了 `ResourceLoader`,这意味着 Spring 上下文本身就是一个资源加载器。
### 五、接口源码
`ResourceLoader` 接口为 Spring 框架定义了资源加载策略。它提供了获取资源的方法,并公开了其使用的 `ClassLoader`。通过这种策略,资源可以从各种来源(如类路径、文件系统等)以统一方式加载。这提供了资源加载的灵活性和一致性,并支持各种资源描述符,如 URL、类路径等。此外它还允许对资源句柄进行多次重新使用和读取。
```java
/**
* 用于加载资源(例如类路径或文件系统资源)的策略接口。
* 一个 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. **`DefaultResourceLoader`**
+ 这是基本的资源加载器实现。它可以处理 "classpath:" 前缀的资源,如果没有提供这样的前缀,它会尝试使用类加载器或文件系统来加载资源。
~~~mermaid
classDiagram
direction BT
class ResourceLoader {
<<interface>>
+ getResource(location) : Resource
+ getClassLoader() : ClassLoader
}
class DefaultResourceLoader {
-ClassLoader classLoader
}
DefaultResourceLoader ..|> ResourceLoader
~~~
### 七、最佳实践
**`DefaultResourceLoader`**
使用 `DefaultResourceLoader` 从不同的资源(类路径和文件系统)加载内容。
```java
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/` 下。
```java
Classpath Exists= true
File Exists = true
```
### 八、与其他组件的关系
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*:" 开头的资源模式,这允许加载所有匹配的资源,而不仅仅是第一个找到的资源。
### 九、常见问题
1. **加载类路径资源**
+ 使用前缀 "classpath:",例如:`loader.getResource("classpath:myconfig.xml")`。
2. **加载文件系统资源**
+ 使用前缀 "file:",例如:`loader.getResource("file:/path/to/myconfig.xml")`。
3. **加载URL资源**
+ 直接使用 URL例如`loader.getResource("http://www.example.com/config.xml")`。
4. **资源不存在**
+ 使用 `Resource.exists()` 方法检查资源是否存在。确保路径或位置正确,并且资源真的存在于预期的位置。
5. **如何读取资源内容**
+ 从 `Resource` 对象中获取 `InputStream`,例如:`resource.getInputStream()`。
6. **`Resource` 获取到文件路径**
+ 使用 `Resource.getFile()`。但请注意这并不总是有效的例如当资源实际上是一个类路径资源或URL资源时。
7. **加载匹配特定模式的多个资源**
+ 使用 `ResourcePatternResolver` 或其实现 `PathMatchingResourcePatternResolver`
8. **自动注入 `ResourceLoader`**
+ 实现 `ResourceLoaderAware` 接口Spring 将自动为我们的 bean 提供 `ResourceLoader` 的引用。
9. **扩展或自定义资源加载机制**
+ 我们可以实现自己的 `ResourceLoader` 或继承现有的实现,如 `DefaultResourceLoader`
11. **加载资源时考虑环境或属性占位符**
+ 使用 `PropertyPlaceholderConfigurer``PropertySourcesPlaceholderConfigurer``@Value` 注解可以解析属性值中的资源路径。