1.优化BeanFactoryAware
2.优化BeanNameAware 3.优化EmbeddedValueResolverAware 4.优化EnvironmentAware 5.优化ImportAware 6.优化MessageSourceAware 7.优化ResourceLoaderAwaremaster
parent
efde86c23a
commit
6a476a9539
|
@ -1,22 +1,28 @@
|
|||
## BeanFactoryAware
|
||||
|
||||
- [BeanFactoryAware](#beanfactoryaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133914782) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [BeanFactoryAware源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-aware/spring-aware-beanFactoryAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`BeanFactoryAware` 接口,允许 Spring bean 获得其所在的 `BeanFactory` 的引用。当一个 bean 实现了这个接口,Spring 容器在初始化该 bean 时,会自动调用 `setBeanFactory()` 方法,并传递一个 `BeanFactory` 实例。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`BeanFactoryAware` 是 Spring 框架自 11.03.2003 开始引入的一个核心接口。允许 Spring beans 获知并与其所在的 `BeanFactory` 进行交互。这为 beans 提供了直接访问 `BeanFactory` 的能力,进而可以查询和交互其他的 beans。
|
||||
|
||||
|
@ -55,15 +61,18 @@ public interface BeanFactoryAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**获取 `BeanFactory` 引用**: 通过实现 `BeanFactoryAware` 接口并重写 `setBeanFactory` 方法,bean 在初始化过程中会收到其所属的 `BeanFactory` 的引用。Spring 容器会自动为实现了该接口的 bean 调用 `setBeanFactory` 方法。
|
||||
1. **获取 `BeanFactory` 引用**
|
||||
+ 通过实现 `BeanFactoryAware` 接口并重写 `setBeanFactory` 方法,bean 在初始化过程中会收到其所属的 `BeanFactory` 的引用。Spring 容器会自动为实现了该接口的 bean 调用 `setBeanFactory` 方法。
|
||||
|
||||
**依赖查找**: 一旦 bean 有了 `BeanFactory` 的引用,它就可以使用这个工厂来动态地查找其他 beans。这种方式被称为“依赖查找”(Dependency Lookup),与常见的“依赖注入”(Dependency Injection)方式相对。
|
||||
2. **依赖查找**
|
||||
+ 一旦 bean 有了 `BeanFactory` 的引用,它就可以使用这个工厂来动态地查找其他 beans。这种方式被称为“依赖查找”(Dependency Lookup),与常见的“依赖注入”(Dependency Injection)方式相对。
|
||||
|
||||
**与 `BeanFactory` 进行交互**: 获取 `BeanFactory` 的引用不仅仅是为了查找其他 beans,bean 还可以与其所在的 `BeanFactory` 进行更广泛的互动,例如检查 bean 的作用域、检查 bean 是否为单例、或获取 bean 的别名等。
|
||||
3. **与 `BeanFactory` 进行交互**
|
||||
+ 获取 `BeanFactory` 的引用不仅仅是为了查找其他 beans,bean 还可以与其所在的 `BeanFactory` 进行更广泛的互动,例如检查 bean 的作用域、检查 bean 是否为单例、或获取 bean 的别名等。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`UserService`类型的bean,最后调用`validateUser`方法。
|
||||
|
||||
|
@ -159,7 +168,7 @@ public class UserService implements BeanFactoryAware, InitializingBean {
|
|||
验证账号密码成功
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -192,7 +201,7 @@ sequenceDiagram
|
|||
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`UserService`类型的bean,最后调用`validateUser`方法。
|
||||
|
||||
|
@ -453,42 +462,58 @@ public class UserService implements BeanFactoryAware, InitializingBean {
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**生命周期时机**:`setBeanFactory` 方法是在 bean 属性设置之后但在其他初始化方法(如 `@PostConstruct`、`InitializingBean#afterPropertiesSet` 或指定的初始化方法)之前调用的。
|
||||
1. **生命周期时机**
|
||||
+ `setBeanFactory` 方法是在 bean 属性设置之后但在其他初始化方法(如 `@PostConstruct`、`InitializingBean#afterPropertiesSet` 或指定的初始化方法)之前调用的。
|
||||
|
||||
**避免循环依赖**:当 beans 通过 `BeanFactory` 查找其他 beans 时,可能会出现循环依赖的情况。例如,bean A 在其 `setBeanFactory` 方法中查找 bean B,而 bean B 在其 `setBeanFactory` 方法中查找 bean A。这种情况会导致容器初始化失败。
|
||||
2. **避免循环依赖**
|
||||
+ 当 beans 通过 `BeanFactory` 查找其他 beans 时,可能会出现循环依赖的情况。例如,bean A 在其 `setBeanFactory` 方法中查找 bean B,而 bean B 在其 `setBeanFactory` 方法中查找 bean A。这种情况会导致容器初始化失败。
|
||||
|
||||
**知道 bean 的作用域**:当从 `BeanFactory` 获取 beans 时,请记住 bean 的作用域。如果 bean 是原型作用域的,每次 `getBean` 调用都会返回一个新的实例。
|
||||
3. **知道 bean 的作用域**
|
||||
+ 当从 `BeanFactory` 获取 beans 时,请记住 bean 的作用域。如果 bean 是原型作用域的,每次 `getBean` 调用都会返回一个新的实例。
|
||||
|
||||
**不要过度自定义**:除非有很好的理由,否则应避免在 `setBeanFactory` 方法中执行大量的自定义逻辑。这会使 bean 的初始化过程变得复杂,并可能导致不可预见的副作用。
|
||||
4. **不要过度自定义**
|
||||
+ 除非有很好的理由,否则应避免在 `setBeanFactory` 方法中执行大量的自定义逻辑。这会使 bean 的初始化过程变得复杂,并可能导致不可预见的副作用。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**构建与配置**:在 `BeanNameAwareApplication` 启动类中,使用了 `AnnotationConfigApplicationContext` 来基于 Java 配置类 (`MyConfiguration`) 初始化 Spring 上下文。这是一个 Java-based 的配置方法,与传统的 XML-based 配置相比,更加直观和灵活。
|
||||
1. **构建与配置**
|
||||
+ 在 `BeanNameAwareApplication` 启动类中,使用了 `AnnotationConfigApplicationContext` 来基于 Java 配置类 (`MyConfiguration`) 初始化 Spring 上下文。这是一个 Java-based 的配置方法,与传统的 XML-based 配置相比,更加直观和灵活。
|
||||
|
||||
**组件扫描**:`MyConfiguration` 配置类使用 `@ComponentScan` 注解指定了需要被扫描的包路径。Spring 容器会自动扫描这些包以及其子包下的组件,并将它们注册为 Spring beans。
|
||||
2. **组件扫描**
|
||||
+ `MyConfiguration` 配置类使用 `@ComponentScan` 注解指定了需要被扫描的包路径。Spring 容器会自动扫描这些包以及其子包下的组件,并将它们注册为 Spring beans。
|
||||
|
||||
**验证器设计**:我们设计了一个 `UserValidator` 接口,以及两个实现该接口的类:`SimpleUserValidator` 和 `ComplexUserValidator`。这两个验证器具有不同的验证逻辑,以满足不同的验证需求。
|
||||
3. **验证器设计**
|
||||
+ 我们设计了一个 `UserValidator` 接口,以及两个实现该接口的类:`SimpleUserValidator` 和 `ComplexUserValidator`。这两个验证器具有不同的验证逻辑,以满足不同的验证需求。
|
||||
|
||||
**动态选择验证器**:`UserService` 类是此应用的核心,它根据某些配置动态地从 `BeanFactory` 中选择一个验证器。这是通过实现 `BeanFactoryAware` 和 `InitializingBean` 接口来完成的:`BeanFactoryAware` 允许 `UserService` 访问 Spring 容器的 `BeanFactory`。InitializingBean` 确保在所有属性(例如依赖注入)设置完毕后,选择合适的验证器。
|
||||
4. **动态选择验证器**
|
||||
+ `UserService` 类是此应用的核心,它根据某些配置动态地从 `BeanFactory` 中选择一个验证器。这是通过实现 `BeanFactoryAware` 和 `InitializingBean` 接口来完成的:`BeanFactoryAware` 允许 `UserService` 访问 Spring 容器的 `BeanFactory`。InitializingBean` 确保在所有属性(例如依赖注入)设置完毕后,选择合适的验证器。
|
||||
|
||||
**运行与输出**:当调用 `validateUser` 方法验证用户名和密码时,根据所选择的验证器(在此示例中是 `SimpleUserValidator`),将输出相应的验证信息。此外,验证器本身也输出了它正在使用的验证方法。
|
||||
5. **运行与输出**
|
||||
+ 当调用 `validateUser` 方法验证用户名和密码时,根据所选择的验证器(在此示例中是 `SimpleUserValidator`),将输出相应的验证信息。此外,验证器本身也输出了它正在使用的验证方法。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**应用启动与上下文初始化**: 当启动类 `BeanNameAwareApplication` 被执行,一个新的 `AnnotationConfigApplicationContext` 被创建并初始化,其中传入了配置类 `MyConfiguration`。
|
||||
1. **应用启动与上下文初始化**
|
||||
+ 当启动类 `BeanNameAwareApplication` 被执行,一个新的 `AnnotationConfigApplicationContext` 被创建并初始化,其中传入了配置类 `MyConfiguration`。
|
||||
|
||||
**配置类与组件扫描**: `MyConfiguration` 是一个 Java 配置类,它告诉 Spring 容器去扫描特定的包以查找组件。
|
||||
2. **配置类与组件扫描**
|
||||
+ `MyConfiguration` 是一个 Java 配置类,它告诉 Spring 容器去扫描特定的包以查找组件。
|
||||
|
||||
**单例bean的预实例化**: 在上下文的 `refresh()` 方法中,Spring 会预先实例化所有非懒加载的单例bean。这意味着在容器启动时,这些bean会被初始化。
|
||||
3. **单例bean的预实例化**
|
||||
+ 在上下文的 `refresh()` 方法中,Spring 会预先实例化所有非懒加载的单例bean。这意味着在容器启动时,这些bean会被初始化。
|
||||
|
||||
**Bean的实例化和初始化**: 在上下文刷新的过程中,Spring 容器会逐个创建并初始化所有的单例bean。`doCreateBean` 方法负责实例化bean、注入依赖、并调用任何初始化方法。
|
||||
4. **Bean的实例化和初始化**
|
||||
+ 在上下文刷新的过程中,Spring 容器会逐个创建并初始化所有的单例bean。`doCreateBean` 方法负责实例化bean、注入依赖、并调用任何初始化方法。
|
||||
|
||||
**处理 Aware 接口**: 对于实现了 `Aware` 接口的bean,如 `BeanFactoryAware`,在初始化过程中,Spring 容器会调用相应的 `Aware` 方法(例如,`setBeanFactory`)。这使得bean可以获得关于其运行环境的信息或其他 Spring 功能。
|
||||
5. **处理 Aware 接口**
|
||||
+ 对于实现了 `Aware` 接口的bean,如 `BeanFactoryAware`,在初始化过程中,Spring 容器会调用相应的 `Aware` 方法(例如,`setBeanFactory`)。这使得bean可以获得关于其运行环境的信息或其他 Spring 功能。
|
||||
|
||||
**自定义逻辑执行**: 一旦bean被初始化,并且所有的 `Aware` 方法都被调用,就可以执行自定义逻辑。在这个例子中,这是通过 `UserService` 的 `validateUser` 方法来完成的。
|
||||
6. **自定义逻辑执行**
|
||||
+ 一旦bean被初始化,并且所有的 `Aware` 方法都被调用,就可以执行自定义逻辑。在这个例子中,这是通过 `UserService` 的 `validateUser` 方法来完成的。
|
||||
|
||||
**BeanFactoryAware 的特性**: 通过实现 `BeanFactoryAware`,`UserService` 能够获得对 `BeanFactory` 的访问权限。这使得它可以在运行时动态地从 `BeanFactory` 中获取bean,如在示例中的 `UserValidator`。
|
||||
7. **BeanFactoryAware 的特性**
|
||||
+ 通过实现 `BeanFactoryAware`,`UserService` 能够获得对 `BeanFactory` 的访问权限。这使得它可以在运行时动态地从 `BeanFactory` 中获取bean,如在示例中的 `UserValidator`。
|
|
@ -1,24 +1,30 @@
|
|||
## BeanNameAware
|
||||
|
||||
- [BeanNameAware](#beannameaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN]() 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [BeanNameAware源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-aware/spring-aware-beanNameAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`BeanNameAware` 接口。当一个 Bean 实现了此接口,可以感知其在 Spring 容器中的名称。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`BeanNameAware` 是 Spring 框架自 01.11.2003 开始引入的一个核心接口。这个接口是为那些想要了解其在 bean 工厂中的名称的 beans 设计的。
|
||||
`BeanNameAware` 是 Spring 框架自 01.11.2003 开始引入的一个核心接口。实现`BeanNameAware`接口的对象会在Spring容器中被自动注入Bean的名称。
|
||||
|
||||
```java
|
||||
/**
|
||||
|
@ -51,15 +57,18 @@ public interface BeanNameAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**提供 `setBeanName` 方法**:当一个 Bean 实现了 `BeanNameAware` 接口,它需要提供 `setBeanName` 方法的实现。这个方法有一个参数,即该 Bean 在 Spring 容器中的名称。
|
||||
1. **提供 `setBeanName` 方法**
|
||||
+ 当一个 Bean 实现了 `BeanNameAware` 接口,它需要提供 `setBeanName` 方法的实现。这个方法有一个参数,即该 Bean 在 Spring 容器中的名称。
|
||||
|
||||
**自动回调**:当 Spring 容器创建并配置一个实现了 `BeanNameAware` 接口的 Bean 时,容器会自动回调 `setBeanName` 方法,并传入该 Bean 在容器中的名称。这意味着开发者不需要显式地调用这个方法;Spring 容器会自动处理。
|
||||
2. **自动回调**
|
||||
+ 当 Spring 容器创建并配置一个实现了 `BeanNameAware` 接口的 Bean 时,容器会自动回调 `setBeanName` 方法,并传入该 Bean 在容器中的名称。这意味着我们不需要显式地调用这个方法;Spring 容器会自动处理。
|
||||
|
||||
**获取 Bean 的名称**:有时,Bean 可能需要知道其在容器中的名称以执行特定的逻辑或功能,或者为了日志记录或其他目的。通过实现 `BeanNameAware`,Bean 可以轻松获得此信息。
|
||||
3. **获取 Bean 的名称**
|
||||
+ 有时,Bean 可能需要知道其在容器中的名称以执行特定的逻辑或功能,或者为了日志记录或其他目的。通过实现 `BeanNameAware`,Bean 可以轻松获得此信息。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。
|
||||
|
||||
|
@ -127,7 +136,7 @@ Module myAliPayService has been registered.
|
|||
Module myWeChatPayService has been registered.
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -159,7 +168,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext-->>BeanNameAwareApplication:初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。
|
||||
|
||||
|
@ -413,42 +422,58 @@ public abstract class MyBasePayService implements BeanNameAware, InitializingBea
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**与其他生命周期方法的顺序**:`setBeanName` 方法的调用是在其他许多生命周期方法之前的,例如 `InitializingBean#afterPropertiesSet` 和任何定义的初始化方法。因此,我们不应该在 `setBeanName` 方法内部预期其他配置或初始化逻辑已经完成。
|
||||
1. **与其他生命周期方法的顺序**
|
||||
+ `setBeanName` 方法的调用是在其他许多生命周期方法之前的,例如 `InitializingBean#afterPropertiesSet` 和任何定义的初始化方法。因此,我们不应该在 `setBeanName` 方法内部预期其他配置或初始化逻辑已经完成。
|
||||
|
||||
**仅在容器管理的 Beans 中有效**:只有当 bean 是由 Spring 容器管理时,`BeanNameAware` 才会生效。简单地创建一个类的实例(例如通过 `new` 关键字)并不会触发 `BeanNameAware` 功能。
|
||||
2. **仅在容器管理的 Beans 中有效**
|
||||
+ 只有当 bean 是由 Spring 容器管理时,`BeanNameAware` 才会生效。简单地创建一个类的实例(例如通过 `new` 关键字)并不会触发 `BeanNameAware` 功能。
|
||||
|
||||
**与其他 Aware 接口的组合使用**:当一个 bean 同时实现多个 `Aware` 接口时,需要注意它们的调用顺序。例如,`BeanNameAware`、`BeanFactoryAware` 和 `ApplicationContextAware` 的回调方法调用顺序是固定的。
|
||||
3. **与其他 Aware 接口的组合使用**
|
||||
+ 当一个 bean 同时实现多个 `Aware` 接口时,需要注意它们的调用顺序。例如,`BeanNameAware`、`BeanFactoryAware` 和 `ApplicationContextAware` 的回调方法调用顺序是固定的。
|
||||
|
||||
**Bean 名称的唯一性**:Spring 容器内的 bean 名称是唯一的,但如果使用别名,同一个 bean 可能会有多个名称。当实现 `BeanNameAware` 时,我们获得的是 bean 的主要名称。
|
||||
4. **Bean 名称的唯一性**
|
||||
+ Spring 容器内的 bean 名称是唯一的,但如果使用别名,同一个 bean 可能会有多个名称。当实现 `BeanNameAware` 时,我们获得的是 bean 的主要名称。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**启动及配置**:我们使用了 `AnnotationConfigApplicationContext` 作为 Spring 容器的入口,专门为基于 Java 的配置设计。该容器被初始化并加载了 `MyConfiguration` 类,它定义了应用的主要配置。
|
||||
1. **启动及配置**
|
||||
+ 我们使用了 `AnnotationConfigApplicationContext` 作为 Spring 容器的入口,专门为基于 Java 的配置设计。该容器被初始化并加载了 `MyConfiguration` 类,它定义了应用的主要配置。
|
||||
|
||||
**组件扫描**:通过在 `MyConfiguration` 类中使用 `@ComponentScan` 注解,我们告诉 Spring 容器去扫描 "`com.xcs.spring.service`" 包及其子包,以找到和管理 Beans。
|
||||
2. **组件扫描**
|
||||
+ 通过在 `MyConfiguration` 类中使用 `@ComponentScan` 注解,我们告诉 Spring 容器去扫描 "`com.xcs.spring.service`" 包及其子包,以找到和管理 Beans。
|
||||
|
||||
**生命周期管理**:**MyBasePayService** 类展示了如何利用 Spring 的特殊接口,例如 `BeanNameAware`、`InitializingBean` 和 `DisposableBean`,来插入到 Bean 的生命周期的特定阶段。当一个 Bean 实例被创建并管理 by Spring, 它会被赋予一个名称(通过 `BeanNameAware`)、在所有属性设置后初始化(通过 `InitializingBean`)以及在应用结束或 Bean 被销毁时执行特定操作(通过 `DisposableBean`)。
|
||||
3. **生命周期管理**
|
||||
+ `MyBasePayService`类展示了如何利用 Spring 的特殊接口,例如 `BeanNameAware`、`InitializingBean` 和 `DisposableBean`,来插入到 Bean 的生命周期的特定阶段。当一个 Bean 实例被创建并管理 by Spring, 它会被赋予一个名称(通过 `BeanNameAware`)、在所有属性设置后初始化(通过 `InitializingBean`)以及在应用结束或 Bean 被销毁时执行特定操作(通过 `DisposableBean`)。
|
||||
|
||||
**具体的服务实现**:有两个具体的支付服务,`MyAliPayService` 和 `MyWeChatPayService`,它们都继承了 `MyBasePayService`。这意味着它们都自动继承了上述的生命周期管理功能。当 Spring 容器启动时,这两个服务的相关生命周期方法会被调用,如我们从打印的消息中所看到的。
|
||||
4. **具体的服务实现**
|
||||
+ 有两个具体的支付服务,`MyAliPayService` 和 `MyWeChatPayService`,它们都继承了 `MyBasePayService`。这意味着它们都自动继承了上述的生命周期管理功能。当 Spring 容器启动时,这两个服务的相关生命周期方法会被调用,如我们从打印的消息中所看到的。
|
||||
|
||||
**实际效果**:当应用运行时,每个服务类都会打印出其已经被注册和注销的消息,这是由于它们都继承了 `MyBasePayService` 中定义的生命周期方法。
|
||||
5. **实际效果**
|
||||
+ 当应用运行时,每个服务类都会打印出其已经被注册和注销的消息,这是由于它们都继承了 `MyBasePayService` 中定义的生命周期方法。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**启动和上下文初始化**:使用`AnnotationConfigApplicationContext`初始化Spring容器,其中传递了配置类`MyConfiguration`。
|
||||
1. **启动和上下文初始化**
|
||||
+ 使用`AnnotationConfigApplicationContext`初始化Spring容器,其中传递了配置类`MyConfiguration`。
|
||||
|
||||
**注册和刷新上下文**:在`AnnotationConfigApplicationContext`构造函数中,`register()`方法注册配置类,而`refresh()`方法开始加载和初始化beans。
|
||||
2. **注册和刷新上下文**
|
||||
+ 在`AnnotationConfigApplicationContext`构造函数中,`register()`方法注册配置类,而`refresh()`方法开始加载和初始化beans。
|
||||
|
||||
**开始bean的实例化**:`refresh()`方法进一步调用了`finishBeanFactoryInitialization(beanFactory)`,该方法负责预先实例化所有非懒加载的单例bean。
|
||||
3. **开始bean的实例化**
|
||||
+ `refresh()`方法进一步调用了`finishBeanFactoryInitialization(beanFactory)`,该方法负责预先实例化所有非懒加载的单例bean。
|
||||
|
||||
**实例化单例bean**:`preInstantiateSingletons()`方法遍历所有bean名称,并通过调用`getBean(beanName)`来实例化和初始化bean。
|
||||
4. **实例化单例bean**
|
||||
+ `preInstantiateSingletons()`方法遍历所有bean名称,并通过调用`getBean(beanName)`来实例化和初始化bean。
|
||||
|
||||
**创建bean实例**:`doGetBean()`是实际进行bean创建的核心方法,它处理了bean的实例化、依赖注入和初始化等逻辑。
|
||||
5. **创建bean实例**
|
||||
+ `doGetBean()`是实际进行bean创建的核心方法,它处理了bean的实例化、依赖注入和初始化等逻辑。
|
||||
|
||||
**处理Aware接口族**:在bean的初始化过程中,`invokeAwareMethods(beanName, bean)`被调用,负责处理实现了`Aware`接口族的beans。这是我们的`BeanNameAware`接口发挥作用的地方,当bean实现此接口时,其`setBeanName`方法会被调用。
|
||||
6. **处理Aware接口族**
|
||||
+ 在bean的初始化过程中,`invokeAwareMethods(beanName, bean)`被调用,负责处理实现了`Aware`接口族的beans。这是我们的`BeanNameAware`接口发挥作用的地方,当bean实现此接口时,其`setBeanName`方法会被调用。
|
||||
|
||||
**用户定义的逻辑**:在`MyBasePayService`类中,我们实现了`BeanNameAware`接口,并重写了`setBeanName`方法来保存bean的名称。此外,还使用了`InitializingBean`和`DisposableBean`接口来在bean的生命周期的特定时刻执行自定义的逻辑。
|
||||
7. **用户定义的逻辑**
|
||||
+ 在`MyBasePayService`类中,我们实现了`BeanNameAware`接口,并重写了`setBeanName`方法来保存bean的名称。此外,还使用了`InitializingBean`和`DisposableBean`接口来在bean的生命周期的特定时刻执行自定义的逻辑。
|
|
@ -1,24 +1,30 @@
|
|||
## EmbeddedValueResolverAware
|
||||
|
||||
- [EmbeddedValueResolverAware](#embeddedvalueresolveraware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133914999) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [EmbeddedValueResolverAware源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-aware/spring-aware-embeddedValueResolverAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`EmbeddedValueResolverAware` 接口,主要用于提供一个字符串值解析器,这可以在 Bean 属性中解析占位符和表达式。如果我们熟悉 Spring 的 `${...}` 占位符和 `#{...}` 表达式,那么这个接口将帮助我们在自定义组件中解析这些值。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`EmbeddedValueResolverAware` 是 Spring 框架自 3.0.3 开始引入的一个核心接口。允许对象在初始化时得到一个 `StringValueResolver`,并使用它来解析嵌入的字符串值,如配置文件中的占位符或 SpEL 表达式。
|
||||
`EmbeddedValueResolverAware` 是 Spring 框架自 3.0.3 开始引入的一个核心接口。实现`EmbeddedValueResolverAware`接口的对象会在Spring容器中被自动注入一个`StringValueResolver`实例。
|
||||
|
||||
```java
|
||||
/**
|
||||
|
@ -44,15 +50,18 @@ public interface EmbeddedValueResolverAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**解析嵌入的字符串值**: 当我们在 Bean 的属性或构造函数参数中有一个值,如 `${property.name}` 或 `#{some.expression}`,这需要被解析成实际的值时,`StringValueResolver` 可以帮助做这件事。
|
||||
1. **解析嵌入的字符串值**
|
||||
+ 当我们在 Bean 的属性或构造函数参数中有一个值,如 `${property.name}` 或 `#{some.expression}`,这需要被解析成实际的值时,`StringValueResolver` 可以帮助做这件事。
|
||||
|
||||
**避免对 `ConfigurableBeanFactory` 的直接依赖**: 通过使用 `EmbeddedValueResolverAware`,我们可以间接地得到这种解析功能,而不必直接依赖于整个 `ConfigurableBeanFactory`。这提供了一种更轻量级、更关注特定功能的方法来解析嵌入的值。
|
||||
2. **避免对 `ConfigurableBeanFactory` 的直接依赖**
|
||||
+ 通过使用 `EmbeddedValueResolverAware`,我们可以间接地得到这种解析功能,而不必直接依赖于整个 `ConfigurableBeanFactory`。这提供了一种更轻量级、更关注特定功能的方法来解析嵌入的值。
|
||||
|
||||
**自动注入 `StringValueResolver`**: 当我们的 Bean 实现了 `EmbeddedValueResolverAware` 接口,Spring 容器会在 Bean 初始化时自动调用 `setEmbeddedValueResolver` 方法,为其注入一个 `StringValueResolver` 实例。这样,Bean 可以在其生命周期中任何时候使用它来解析字符串值。
|
||||
3. **自动注入 `StringValueResolver`**
|
||||
+ 当我们的 Bean 实现了 `EmbeddedValueResolverAware` 接口,Spring 容器会在 Bean 初始化时自动调用 `setEmbeddedValueResolver` 方法,为其注入一个 `StringValueResolver` 实例。这样,Bean 可以在其生命周期中任何时候使用它来解析字符串值。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyEmbeddedValueResolverAware`类型的bean,最后调用`resolve`方法。
|
||||
|
||||
|
@ -105,7 +114,7 @@ public class MyEmbeddedValueResolverAware implements EmbeddedValueResolverAware
|
|||
Hello, Lex! Today is 2023-10-03
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -140,7 +149,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext-->>EmbeddedValueResolverAwareApplication:初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyEmbeddedValueResolverAware`类型的bean,最后调用`resolve`方法。
|
||||
|
||||
|
@ -427,48 +436,67 @@ public class MyEmbeddedValueResolverAware implements EmbeddedValueResolverAware
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**正确的环境**: 确保你在 Spring 的环境中使用它,因为 `StringValueResolver` 需要 Spring 上下文来正确解析嵌入的值。
|
||||
1. **正确的环境**
|
||||
+ 确保我们在 Spring 的环境中使用它,因为 `StringValueResolver` 需要 Spring 上下文来正确解析嵌入的值。
|
||||
|
||||
**非延迟依赖注入**: `setEmbeddedValueResolver` 方法在 Bean 初始化时调用。如果你太早地尝试使用 `StringValueResolver`(例如,在构造函数中),它可能还没有被注入。
|
||||
2. **非延迟依赖注入**
|
||||
+ `setEmbeddedValueResolver` 方法在 Bean 初始化时调用。如果我们太早地尝试使用 `StringValueResolver`(例如,在构造函数中),它可能还没有被注入。
|
||||
|
||||
**默认值**: 当使用 `${user.name:xcs}` 语法时,如果 `user.name` 没有在环境中定义,它将使用 `xcs`。这可以避免因缺少配置而导致的错误。
|
||||
3. **默认值**
|
||||
+ 当使用 `${user.name:xcs}` 语法时,如果 `user.name` 没有在环境中定义,它将使用 `xcs`。这可以避免因缺少配置而导致的错误。
|
||||
|
||||
**明确解析的范围**: `EmbeddedValueResolverAware` 通常用于解析占位符和 SpEL 表达式。确保不将它与更复杂的 Bean 解析逻辑混淆。
|
||||
4. **明确解析的范围**
|
||||
+ `EmbeddedValueResolverAware` 通常用于解析占位符和 SpEL 表达式。确保不将它与更复杂的 Bean 解析逻辑混淆。
|
||||
|
||||
**错误处理**: 当解析一个字符串值失败时,Spring 通常会抛出一个异常。确保在代码中适当地处理这些异常。
|
||||
5. **错误处理**
|
||||
+ 当解析一个字符串值失败时,Spring 通常会抛出一个异常。确保在代码中适当地处理这些异常。
|
||||
|
||||
**与其他 Aware 接口的交互**: 如果你的 Bean 实现了多个 `Aware` 接口,需要确保你理解了每个接口的初始化时机和顺序,以及如何与其他 Aware 方法(如 `setBeanFactory` 或 `setApplicationContext`)交互。
|
||||
6. **与其他 Aware 接口的交互**
|
||||
+ 如果我们的 Bean 实现了多个 `Aware` 接口,需要确保我们理解了每个接口的初始化时机和顺序,以及如何与其他 Aware 方法(如 `setBeanFactory` 或 `setApplicationContext`)交互。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**启动类**:在 `EmbeddedValueResolverAwareApplication` 中,我们初始化了 Spring 的 `AnnotationConfigApplicationContext` 并加载了 `MyConfiguration` 作为配置类。接着,我们从上下文中取得 `MyEmbeddedValueResolverAware` 的 Bean,并调用了其 `resolve` 方法。
|
||||
1. **启动类**
|
||||
+ 在 `EmbeddedValueResolverAwareApplication` 中,我们初始化了 Spring 的 `AnnotationConfigApplicationContext` 并加载了 `MyConfiguration` 作为配置类。接着,我们从上下文中取得 `MyEmbeddedValueResolverAware` 的 Bean,并调用了其 `resolve` 方法。
|
||||
|
||||
**配置与Bean声明**:在 `MyConfiguration` 配置类中,我们声明了 `MyEmbeddedValueResolverAware` 为一个 Bean,这确保了它会被 Spring 容器管理,并且会接收到 `StringValueResolver` 的实例注入。
|
||||
2. **配置与Bean声明**
|
||||
+ 在 `MyConfiguration` 配置类中,我们声明了 `MyEmbeddedValueResolverAware` 为一个 Bean,这确保了它会被 Spring 容器管理,并且会接收到 `StringValueResolver` 的实例注入。
|
||||
|
||||
**嵌入值解析**:`MyEmbeddedValueResolverAware` 类实现了 `EmbeddedValueResolverAware` 接口,这意味着在该 Bean 被初始化时,Spring 会自动提供一个 `StringValueResolver` 实例。这个解析器之后被用于解析字符串 "Hello, ${user.name:xcs}! Today is #{T(java.time.LocalDate).now().toString()}"。
|
||||
3. **嵌入值解析**
|
||||
+ `MyEmbeddedValueResolverAware` 类实现了 `EmbeddedValueResolverAware` 接口,这意味着在该 Bean 被初始化时,Spring 会自动提供一个 `StringValueResolver` 实例。这个解析器之后被用于解析字符串 "Hello, ${user.name:xcs}! Today is #{T(java.time.LocalDate).now().toString()}"。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**应用启动**:在`EmbeddedValueResolverAwareApplication`类中,使用`AnnotationConfigApplicationContext`来启动Spring应用并加载`MyConfiguration`配置类。
|
||||
1. **应用启动**
|
||||
+ 在`EmbeddedValueResolverAwareApplication`类中,使用`AnnotationConfigApplicationContext`来启动Spring应用并加载`MyConfiguration`配置类。
|
||||
|
||||
**容器初始化**:在构造函数`AnnotationConfigApplicationContext`中,`refresh()`方法被调用来初始化Spring容器。
|
||||
2. **容器初始化**
|
||||
+ 在构造函数`AnnotationConfigApplicationContext`中,`refresh()`方法被调用来初始化Spring容器。
|
||||
|
||||
**实例化Beans**:在`AbstractApplicationContext`的`refresh()`方法中,`finishBeanFactoryInitialization`方法被调用,确保所有单例Bean被预先实例化。
|
||||
3. **实例化Beans**
|
||||
+ 在`AbstractApplicationContext`的`refresh()`方法中,`finishBeanFactoryInitialization`方法被调用,确保所有单例Bean被预先实例化。
|
||||
|
||||
**Bean预实例化**:`DefaultListableBeanFactory`的`preInstantiateSingletons`方法确保所有非懒加载的单例Beans被实例化。核心操作是调用`getBean(beanName)`。
|
||||
4. **Bean预实例化**
|
||||
+ `DefaultListableBeanFactory`的`preInstantiateSingletons`方法确保所有非懒加载的单例Beans被实例化。核心操作是调用`getBean(beanName)`。
|
||||
|
||||
**获取Bean实例**:`AbstractBeanFactory`的`getBean`方法进一步调用`doGetBean`来真正实例化Bean,处理异常和依赖,并返回Bean实例。
|
||||
5. **获取Bean实例**
|
||||
+ `AbstractBeanFactory`的`getBean`方法进一步调用`doGetBean`来真正实例化Bean,处理异常和依赖,并返回Bean实例。
|
||||
|
||||
**Bean单例获取**:`DefaultSingletonBeanRegistry`的`getSingleton`方法确保Bean以单例形式存在,从缓存获取或使用提供的`ObjectFactory`创建新实例。
|
||||
6. **Bean单例获取**
|
||||
+ `DefaultSingletonBeanRegistry`的`getSingleton`方法确保Bean以单例形式存在,从缓存获取或使用提供的`ObjectFactory`创建新实例。
|
||||
|
||||
**创建Bean实例**:`AbstractAutowireCapableBeanFactory`的`createBean`方法调用`doCreateBean`进行Bean的实际实例化,并进行初始化,确保Bean完全配置并准备就绪。
|
||||
7. **创建Bean实例**
|
||||
+ `AbstractAutowireCapableBeanFactory`的`createBean`方法调用`doCreateBean`进行Bean的实际实例化,并进行初始化,确保Bean完全配置并准备就绪。
|
||||
|
||||
**Bean初始化**:`AbstractAutowireCapableBeanFactory`的`initializeBean`方法确保Bean被正确初始化,其中调用`applyBeanPostProcessorsBeforeInitialization`方法是Spring生命周期中的关键点,允许BeanPostProcessors在Bean初始化之前进行操作。
|
||||
8. **Bean初始化**
|
||||
+ `AbstractAutowireCapableBeanFactory`的`initializeBean`方法确保Bean被正确初始化,其中调用`applyBeanPostProcessorsBeforeInitialization`方法是Spring生命周期中的关键点,允许BeanPostProcessors在Bean初始化之前进行操作。
|
||||
|
||||
**处理Aware接口**:在Bean初始化过程中,`ApplicationContextAwareProcessor`确保实现了`Aware`接口的Beans被正确处理,这些Beans会自动"感知"并获得其运行环境或特定依赖的引用。
|
||||
9. **处理Aware接口**
|
||||
+ 在Bean初始化过程中,`ApplicationContextAwareProcessor`确保实现了`Aware`接口的Beans被正确处理,这些Beans会自动"感知"并获得其运行环境或特定依赖的引用。
|
||||
|
||||
**值解析**:最后,我们的`MyEmbeddedValueResolverAware` Bean接收到了一个`StringValueResolver`实例。此时,当`resolve`方法被调用,它会使用这个解析器来解析嵌入的字符串值,并打印到控制台。
|
||||
10. **值解析**
|
||||
+ 最后,我们的`MyEmbeddedValueResolverAware` Bean接收到了一个`StringValueResolver`实例。此时,当`resolve`方法被调用,它会使用这个解析器来解析嵌入的字符串值,并打印到控制台。
|
|
@ -1,24 +1,30 @@
|
|||
## EnvironmentAware
|
||||
|
||||
- [EnvironmentAware](#environmentaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133915522) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [EnvironmentAware源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-aware/spring-aware-environmentAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`EnvironmentAware` 接口,允许Beans访问`Environment`对象。这是一个回调接口,当实现该接口的Bean被Spring容器管理时,Spring容器会为该Bean设置`Environment`对象。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`EnvironmentAware` 是 Spring 框架自 3.1 开始引入的一个核心接口。主要目的是允许bean在运行时获取与其运行环境有关的信息。这包括环境属性、配置文件、激活的profile等。
|
||||
`EnvironmentAware` 是 Spring 框架自 3.1 开始引入的一个核心接口。实现`EnvironmentAware`接口的对象会在Spring容器中被自动注入一个`Environment`实例。
|
||||
|
||||
```java
|
||||
/**
|
||||
|
@ -37,17 +43,21 @@ public interface EnvironmentAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**访问环境属性**:通过实现 `EnvironmentAware`,beans 可以直接访问应用上下文的`Environment`对象。这意味着它们可以读取环境属性,这些属性可能来自多个来源,例如系统属性、JVM参数、操作系统环境变量、属性文件等。
|
||||
1. **访问环境属性**
|
||||
+ 通过实现 `EnvironmentAware`,beans 可以直接访问应用上下文的`Environment`对象。这意味着它们可以读取环境属性,这些属性可能来自多个来源,例如系统属性、JVM参数、操作系统环境变量、属性文件等。
|
||||
|
||||
**识别运行时环境**:beans可以通过`Environment`对象来检查和确定当前激活的Spring profiles。这使得bean可以根据不同的运行环境(例如开发、测试、生产等)进行特定的操作或配置。
|
||||
2. **识别运行时环境**
|
||||
+ beans可以通过`Environment`对象来检查和确定当前激活的Spring profiles。这使得bean可以根据不同的运行环境(例如开发、测试、生产等)进行特定的操作或配置。
|
||||
|
||||
**自动回调**:当Spring容器识别到一个bean实现了`EnvironmentAware`接口时,容器会自动调用 `setEnvironment` 方法并传递当前的 `Environment` 对象。这意味着开发者不需要特意去手动设置或获取它。
|
||||
3. **自动回调**
|
||||
+ 当Spring容器识别到一个bean实现了`EnvironmentAware`接口时,容器会自动调用 `setEnvironment` 方法并传递当前的 `Environment` 对象。这意味着我们不需要特意去手动设置或获取它。
|
||||
|
||||
**框架级别的集成**:此接口提供了一个标准机制,允许框架级别的代码(如其他Spring组件和第三方库)访问和集成`Environment`对象,而不必依赖特定的注入策略或其他机制。
|
||||
4. **框架级别的集成**
|
||||
+ 此接口提供了一个标准机制,允许框架级别的代码(如其他Spring组件和第三方库)访问和集成`Environment`对象,而不必依赖特定的注入策略或其他机制。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyEnvironmentAware`类型的bean,最后调用`getAppProperty`方法并打印。
|
||||
|
||||
|
@ -101,7 +111,7 @@ public class MyEnvironmentAware implements EnvironmentAware {
|
|||
AppProperty = Hello from EnvironmentAware!
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -136,7 +146,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext-->>EnvironmentAwareApplication:初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyEnvironmentAware`类型的bean,最后调用`getAppProperty`方法并打印。
|
||||
|
||||
|
@ -421,44 +431,61 @@ public class MyEnvironmentAware implements EnvironmentAware {
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**不要过度使用**:虽然`EnvironmentAware`为Bean提供了一个直接访问`Environment`的方法,但这并不意味着所有的Bean都应该使用它。在可能的情况下,首先考虑使用Spring的属性注入功能,例如`@Value`。
|
||||
1. **不要过度使用**
|
||||
+ 虽然`EnvironmentAware`为Bean提供了一个直接访问`Environment`的方法,但这并不意味着所有的Bean都应该使用它。在可能的情况下,首先考虑使用Spring的属性注入功能,例如`@Value`。
|
||||
|
||||
**避免使用硬编码的属性键**:当从`Environment`对象中获取属性时,尽量避免在代码中硬编码属性键。最好是将这些键作为常量或在外部配置中定义。
|
||||
2. **避免使用硬编码的属性键**
|
||||
+ 当从`Environment`对象中获取属性时,尽量避免在代码中硬编码属性键。最好是将这些键作为常量或在外部配置中定义。
|
||||
|
||||
**处理不存在的属性**:当使用`Environment`获取属性时,如果该属性不存在,`Environment`可能会返回`null`。确保在代码中正确处理这种情况,或使用`Environment`提供的默认值方法。
|
||||
3. **处理不存在的属性**
|
||||
+ 当使用`Environment`获取属性时,如果该属性不存在,`Environment`可能会返回`null`。确保在代码中正确处理这种情况,或使用`Environment`提供的默认值方法。
|
||||
|
||||
**记住激活的配置文件**:`Environment`允许我们查询当前激活的配置文件(profiles)。确保我们知道哪些profiles是激活的,尤其是在使用特定于profile的属性时。
|
||||
4. **记住激活的配置文件**
|
||||
+ `Environment`允许我们查询当前激活的配置文件(profiles)。确保我们知道哪些profiles是激活的,尤其是在使用特定于profile的属性时。
|
||||
|
||||
**了解Environment的层次结构**:`Environment`对象可能会从多个来源获取属性(例如系统属性、环境变量、配置文件等)。了解这些来源的优先级和加载顺序,以便正确地理解在存在冲突时哪个属性值会被使用。
|
||||
5. **了解Environment的层次结构**
|
||||
+ `Environment`对象可能会从多个来源获取属性(例如系统属性、环境变量、配置文件等)。了解这些来源的优先级和加载顺序,以便正确地理解在存在冲突时哪个属性值会被使用。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**启动过程**:通过`EnvironmentAwareApplication`作为主入口,我们使用了`AnnotationConfigApplicationContext`来启动Spring上下文,并加载了`MyConfiguration`作为配置类。
|
||||
1. **启动过程**
|
||||
+ 通过`EnvironmentAwareApplication`作为主入口,我们使用了`AnnotationConfigApplicationContext`来启动Spring上下文,并加载了`MyConfiguration`作为配置类。
|
||||
|
||||
**加载属性**:在`MyConfiguration`类中,我们使用了`@PropertySource`注解指定了从类路径下的`application.properties`文件加载属性到Spring的环境中。
|
||||
2. **加载属性**
|
||||
+ 在`MyConfiguration`类中,我们使用了`@PropertySource`注解指定了从类路径下的`application.properties`文件加载属性到Spring的环境中。
|
||||
|
||||
**注册Bean**:在配置类`MyConfiguration`中,我们定义了一个bean `MyEnvironmentAware`。这保证了当Spring容器启动时,`MyEnvironmentAware`对象会被创建并由Spring管理。
|
||||
3. **注册Bean**
|
||||
+ 在配置类`MyConfiguration`中,我们定义了一个bean `MyEnvironmentAware`。这保证了当Spring容器启动时,`MyEnvironmentAware`对象会被创建并由Spring管理。
|
||||
|
||||
**访问环境属性**:`MyEnvironmentAware`类实现了`EnvironmentAware`接口,这使得当Spring容器初始化该bean时,它会自动调用`setEnvironment`方法,注入当前的`Environment`对象。我们使用这个方法来读取`app.xcs.property`属性,并将其值存储在`appProperty`私有变量中。
|
||||
4. **访问环境属性**
|
||||
+ `MyEnvironmentAware`类实现了`EnvironmentAware`接口,这使得当Spring容器初始化该bean时,它会自动调用`setEnvironment`方法,注入当前的`Environment`对象。我们使用这个方法来读取`app.xcs.property`属性,并将其值存储在`appProperty`私有变量中。
|
||||
|
||||
**显示属性**:最后,在`EnvironmentAwareApplication`主程序中,我们从Spring上下文中获取了`MyEnvironmentAware` bean,并调用了`getAppProperty`方法来获取属性值,然后将其打印到控制台。
|
||||
5. **显示属性**
|
||||
+ 最后,在`EnvironmentAwareApplication`主程序中,我们从Spring上下文中获取了`MyEnvironmentAware` bean,并调用了`getAppProperty`方法来获取属性值,然后将其打印到控制台。
|
||||
|
||||
**输出**:结果显示为“AppProperty = Hello from EnvironmentAware!”,这证明了`EnvironmentAware`接口和`application.properties`文件成功地结合起来,并且我们已经成功地使用Spring环境获取了配置属性。
|
||||
6. **输出**
|
||||
+ 结果显示为“AppProperty = Hello from EnvironmentAware!”,这证明了`EnvironmentAware`接口和`application.properties`文件成功地结合起来,并且我们已经成功地使用Spring环境获取了配置属性。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**应用启动**: 通过`EnvironmentAwareApplication`作为入口,使用`AnnotationConfigApplicationContext`来初始化Spring的上下文,并加载`MyConfiguration`作为配置类。
|
||||
1. **应用启动**
|
||||
+ 通过`EnvironmentAwareApplication`作为入口,使用`AnnotationConfigApplicationContext`来初始化Spring的上下文,并加载`MyConfiguration`作为配置类。
|
||||
|
||||
**属性加载**: 在`MyConfiguration`类中,利用`@PropertySource`注解,指定从`application.properties`文件加载属性到Spring环境中。
|
||||
2. **属性加载**
|
||||
+ 在`MyConfiguration`类中,利用`@PropertySource`注解,指定从`application.properties`文件加载属性到Spring环境中。
|
||||
|
||||
**Bean注册与初始化**: 在上下文的`refresh()`方法中,调用`finishBeanFactoryInitialization()`确保所有非懒加载的单例bean都被实例化。这个过程在`preInstantiateSingletons()`中通过循环调用`getBean()`完成,该方法将触发bean的创建、初始化及其依赖的注入。
|
||||
3. **Bean注册与初始化**
|
||||
+ 在上下文的`refresh()`方法中,调用`finishBeanFactoryInitialization()`确保所有非懒加载的单例bean都被实例化。这个过程在`preInstantiateSingletons()`中通过循环调用`getBean()`完成,该方法将触发bean的创建、初始化及其依赖的注入。
|
||||
|
||||
**Bean后处理与"感知"**: 在bean的初始化过程中,`ApplicationContextAwareProcessor`负责检查并调用那些实现了Aware接口的bean的特定方法。对于实现了`EnvironmentAware`接口的beans,它会调用`setEnvironment()`方法并传入当前的`Environment`对象。
|
||||
4. **Bean后处理与"感知"**
|
||||
+ 在bean的初始化过程中,`ApplicationContextAwareProcessor`负责检查并调用那些实现了Aware接口的bean的特定方法。对于实现了`EnvironmentAware`接口的beans,它会调用`setEnvironment()`方法并传入当前的`Environment`对象。
|
||||
|
||||
**自定义Bean的处理**: `MyEnvironmentAware`在其`setEnvironment()`方法中,从传入的`Environment`对象中获取了`app.xcs.property`属性,并存储到了它的私有变量`appProperty`中。
|
||||
5. **自定义Bean的处理**
|
||||
+ `MyEnvironmentAware`在其`setEnvironment()`方法中,从传入的`Environment`对象中获取了`app.xcs.property`属性,并存储到了它的私有变量`appProperty`中。
|
||||
|
||||
**应用结果输出**: 在`EnvironmentAwareApplication`的主方法中,从Spring上下文获取了`MyEnvironmentAware` bean并调用其`getAppProperty()`方法,然后将获得的属性值输出到控制台。
|
||||
6. **应用结果输出**
|
||||
+ 在`EnvironmentAwareApplication`的主方法中,从Spring上下文获取了`MyEnvironmentAware` bean并调用其`getAppProperty()`方法,然后将获得的属性值输出到控制台。
|
|
@ -1,22 +1,28 @@
|
|||
## ImportAware
|
||||
|
||||
- [ImportAware](#importaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133915616) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [ImportAware源码]()
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`ImportAware` 接口,提供被导入类的访问功能。当一个类实现了 `ImportAware` 接口,并且被通过 @Import 注解导入到其他配置类中,该类可以获得对导入它的 `AnnotationMetadata` 的访问权。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`ApplicationStartupAware` 是 Spring 框架自 3.1 开始引入的一个核心接口。实现`ImportAware`接口的对象会在Spring容器中被自动注入一个`AnnotationMetadata`实例。
|
||||
|
||||
|
@ -38,17 +44,21 @@ public interface ImportAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**访问导入类的注解元数据**:当一个类实现了 `ImportAware` 接口,并且它是通过 `@Import` 或其他特定方式被导入的,Spring 容器会自动调用它的 `setImportMetadata` 方法,并传入与导入该类的注解相关的 `AnnotationMetadata`。
|
||||
1. **访问导入类的注解元数据**
|
||||
+ 当一个类实现了 `ImportAware` 接口,并且它是通过 `@Import` 或其他特定方式被导入的,Spring 容器会自动调用它的 `setImportMetadata` 方法,并传入与导入该类的注解相关的 `AnnotationMetadata`。
|
||||
|
||||
**条件性的行为**:通过访问导入类的注解元数据,可以实现基于特定条件的行为。例如,根据导入类上的注解属性,决定是否注册某个 bean,或者为 bean 设置特定的属性值。
|
||||
2. **条件性的行为**
|
||||
+ 通过访问导入类的注解元数据,可以实现基于特定条件的行为。例如,根据导入类上的注解属性,决定是否注册某个 bean,或者为 bean 设置特定的属性值。
|
||||
|
||||
**框架和库的开发**:`ImportAware` 在 Spring 框架内部和某些第三方库中被用于执行特定的初始化和配置任务。例如,某些特性的自动配置可能会根据导入它们的配置类上的注解属性进行调整。
|
||||
3. **框架和库的开发**
|
||||
+ `ImportAware` 在 Spring 框架内部和某些第三方库中被用于执行特定的初始化和配置任务。例如,某些特性的自动配置可能会根据导入它们的配置类上的注解属性进行调整。
|
||||
|
||||
**增强诊断和调试信息**:可以基于导入类的元数据为我们提供更多的上下文信息,这在诊断复杂的配置问题时可能会很有用。
|
||||
4. **增强诊断和调试信息**
|
||||
+ 可以基于导入类的元数据为我们提供更多的上下文信息,这在诊断复杂的配置问题时可能会很有用。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`String`类型的bean并打印。
|
||||
|
||||
|
@ -137,9 +147,7 @@ Caused by: java.lang.IllegalArgumentException: @EnableXcs is not present on impo
|
|||
... 10 more
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -174,7 +182,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext->>ImportAwareApplication: 初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`String`类型的bean并打印。
|
||||
|
||||
|
@ -450,44 +458,61 @@ public class MyImportAware implements ImportAware {
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**明确需求**:在决定实现 `ImportAware` 之前,请确保您确实需要知道是哪个类导入了您的组件,并且需要访问其注解元数据。避免不必要的复杂性。
|
||||
1. **明确需求**
|
||||
+ 在决定实现 `ImportAware` 之前,请确保我们确实需要知道是哪个类导入了我们的组件,并且需要访问其注解元数据。避免不必要的复杂性。
|
||||
|
||||
**正确的上下文**:`ImportAware` 只对通过 `@Import` 导入的类有意义。对于其他方式注册的 beans(例如,通过 component scanning 或 XML 配置),`setImportMetadata` 方法可能不会被调用。
|
||||
2. **正确的上下文**
|
||||
+ `ImportAware` 只对通过 `@Import` 导入的类有意义。对于其他方式注册的 beans(例如,通过 component scanning 或 XML 配置),`setImportMetadata` 方法可能不会被调用。
|
||||
|
||||
**小心处理元数据**:当访问 `AnnotationMetadata` 时,确保处理不存在的注解或属性的情况,以避免空指针异常。
|
||||
3. **小心处理元数据**
|
||||
+ 当访问 `AnnotationMetadata` 时,确保处理不存在的注解或属性的情况,以避免空指针异常。
|
||||
|
||||
**注意与其他 `BeanPostProcessor` 的交互**:`ImportAware` 的功能部分是通过 `BeanPostProcessor` 机制实现的。如果您在应用中使用其他 `BeanPostProcessor`,请确保您了解它们之间的交互和执行顺序。
|
||||
4. **注意与其他 `BeanPostProcessor` 的交互**
|
||||
+ `ImportAware` 的功能部分是通过 `BeanPostProcessor` 机制实现的。如果我们在应用中使用其他 `BeanPostProcessor`,请确保我们了解它们之间的交互和执行顺序。
|
||||
|
||||
**不要过度使用**:虽然 `ImportAware` 可以带来一些灵活性,但不应在不需要的地方使用它。过度使用可能会导致配置变得复杂且难以追踪。
|
||||
5. **不要过度使用**
|
||||
+ 虽然 `ImportAware` 可以带来一些灵活性,但不应在不需要的地方使用它。过度使用可能会导致配置变得复杂且难以追踪。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**初始化与运行**:使用 `AnnotationConfigApplicationContext` 初始化了一个 Spring 上下文,加载了 `MyConfiguration` 配置类,并从上下文中获取了一个类型为 `String` 的 bean。
|
||||
1. **初始化与运行**
|
||||
+ 使用 `AnnotationConfigApplicationContext` 初始化了一个 Spring 上下文,加载了 `MyConfiguration` 配置类,并从上下文中获取了一个类型为 `String` 的 bean。
|
||||
|
||||
**`@EnableXcs` 注解的作用**:`@EnableXcs` 是一个自定义注解,其主要作用是通过 `@Import` 注解导入 `MyImportAware` 类,从而启动 `ImportAware` 功能。
|
||||
2. **`@EnableXcs` 注解的作用**
|
||||
+ `@EnableXcs` 是一个自定义注解,其主要作用是通过 `@Import` 注解导入 `MyImportAware` 类,从而启动 `ImportAware` 功能。
|
||||
|
||||
**`MyImportAware` 类与 `ImportAware`**:`MyImportAware` 实现了 `ImportAware` 接口,允许它获取关于导入它的类的注解信息。在 `setImportMetadata` 方法中,`MyImportAware` 会检查导入它的类是否有 `@EnableXcs` 注解。如果存在 `@EnableXcs` 注解,它会继续并注册一个 `String` 类型的 bean,值为 "This is a custom bean!"。如果不存在,它会抛出异常,提示 `@EnableXcs` 注解不存在于导入它的类上。
|
||||
3. **`MyImportAware` 类与 `ImportAware`**
|
||||
+ `MyImportAware` 实现了 `ImportAware` 接口,允许它获取关于导入它的类的注解信息。在 `setImportMetadata` 方法中,`MyImportAware` 会检查导入它的类是否有 `@EnableXcs` 注解。如果存在 `@EnableXcs` 注解,它会继续并注册一个 `String` 类型的 bean,值为 "This is a custom bean!"。如果不存在,它会抛出异常,提示 `@EnableXcs` 注解不存在于导入它的类上。
|
||||
|
||||
**正常使用**:当 `MyConfiguration` 使用 `@EnableXcs` 注解时,程序可以正常运行,从上下文中获取到的 String 类型的 bean 值为 "This is a custom bean!"。
|
||||
4. **正常使用**
|
||||
+ 当 `MyConfiguration` 使用 `@EnableXcs` 注解时,程序可以正常运行,从上下文中获取到的 String 类型的 bean 值为 "This is a custom bean!"。
|
||||
|
||||
**异常情况**:但如果 `MyConfiguration` 直接使用 `@Import(MyImportAware.class)` 导入 `MyImportAware` 类,而不使用 `@EnableXcs` 注解,会导致 `MyImportAware` 在查找 `@EnableXcs` 注解时发现它不存在,从而抛出异常。
|
||||
5. **异常情况**
|
||||
+ 但如果 `MyConfiguration` 直接使用 `@Import(MyImportAware.class)` 导入 `MyImportAware` 类,而不使用 `@EnableXcs` 注解,会导致 `MyImportAware` 在查找 `@EnableXcs` 注解时发现它不存在,从而抛出异常。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**应用程序启动**: 使用 `AnnotationConfigApplicationContext` 初始化 Spring 上下文,加载 `MyConfiguration` 配置类。程序试图从 Spring 上下文中获取一个类型为 `String` 的 bean。
|
||||
1. **应用程序启动**
|
||||
+ 使用 `AnnotationConfigApplicationContext` 初始化 Spring 上下文,加载 `MyConfiguration` 配置类。程序试图从 Spring 上下文中获取一个类型为 `String` 的 bean。
|
||||
|
||||
**上下文刷新**: 在构造 `AnnotationConfigApplicationContext` 时,会调用 `refresh()` 方法,这是 Spring 上下文的初始化和刷新过程的入口点。
|
||||
2. **上下文刷新**
|
||||
+ 在构造 `AnnotationConfigApplicationContext` 时,会调用 `refresh()` 方法,这是 Spring 上下文的初始化和刷新过程的入口点。
|
||||
|
||||
**实例化Beans**: 执行 `finishBeanFactoryInitialization`,该方法负责预实例化上下文中的所有非懒加载单例bean。对于每个bean,它都会调用 `getBean` 方法。
|
||||
3. **实例化Beans**
|
||||
+ 执行 `finishBeanFactoryInitialization`,该方法负责预实例化上下文中的所有非懒加载单例bean。对于每个bean,它都会调用 `getBean` 方法。
|
||||
|
||||
**处理 `ImportAware` Beans**: 如果bean实现了 `ImportAware` 接口,`postProcessBeforeInitialization` 方法会为该 bean 设置导入它的类的注解元数据。在我们的例子中,`MyImportAware` 就是这样一个bean。
|
||||
4. **处理 `ImportAware` Beans**
|
||||
+ 如果bean实现了 `ImportAware` 接口,`postProcessBeforeInitialization` 方法会为该 bean 设置导入它的类的注解元数据。在我们的例子中,`MyImportAware` 就是这样一个bean。
|
||||
|
||||
**检查 `@EnableXcs`**: 在 `MyImportAware` 的 `setImportMetadata` 方法中,它会检查导入它的类是否有 `@EnableXcs` 注解。如果存在该注解,则继续处理;如果不存在,则抛出异常。
|
||||
5. **检查 `@EnableXcs`**
|
||||
+ 在 `MyImportAware` 的 `setImportMetadata` 方法中,它会检查导入它的类是否有 `@EnableXcs` 注解。如果存在该注解,则继续处理;如果不存在,则抛出异常。
|
||||
|
||||
**Bean创建**: 如果导入类上存在 `@EnableXcs` 注解,`MyImportAware` 继续并定义了一个 `String` 类型的 bean。这就是我们从上下文中检索并在控制台上打印的bean。
|
||||
6. **Bean创建**
|
||||
+ 如果导入类上存在 `@EnableXcs` 注解,`MyImportAware` 继续并定义了一个 `String` 类型的 bean。这就是我们从上下文中检索并在控制台上打印的bean。
|
||||
|
||||
**异常处理**: 如果直接使用 `@Import` 导入 `MyImportAware` 而不使用 `@EnableXcs` 注解,会发生异常,因为 `MyImportAware` 期望导入它的类上有 `@EnableXcs` 注解。
|
||||
7. **异常处理**
|
||||
+ 如果直接使用 `@Import` 导入 `MyImportAware` 而不使用 `@EnableXcs` 注解,会发生异常,因为 `MyImportAware` 期望导入它的类上有 `@EnableXcs` 注解。
|
|
@ -1,22 +1,28 @@
|
|||
## MessageSourceAware
|
||||
|
||||
- [MessageSourceAware](#messagesourceaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
`MessageSourceAware` 接口,主要用于对象希望被注入`MessageSource`。`MessageSource`是Spring中用于国际化(i18n)的接口,它提供了从不同的消息资源(例如:属性文件)获取消息的方法。使用`MessageSource`,你可以为应用程序提供国际化的消息支持。
|
||||
### 一、基本信息
|
||||
|
||||
### 二、接口源码
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133915709) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [MessageSourceAware源码](https://github.com/xuchengsheng/spring-reading/blob/master/spring-aware/spring-aware-messageSourceAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`MessageSourceAware` 接口,主要用于对象希望被注入`MessageSource`。`MessageSource`是Spring中用于国际化(i18n)的接口,它提供了从不同的消息资源(例如:属性文件)获取消息的方法。使用`MessageSource`,我们可以为应用程序提供国际化的消息支持。
|
||||
|
||||
### 三、接口源码
|
||||
|
||||
`MessageSourceAware` 是 Spring 框架自 1.1.1 开始引入的一个核心接口。实现`MessageSourceAware`接口的对象会在Spring容器中被自动注入一个`MessageSource`实例。
|
||||
|
||||
|
@ -45,15 +51,18 @@ public interface MessageSourceAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**自动注入**:当一个bean实现了`MessageSourceAware`接口,并且被Spring容器管理时,Spring将会自动调用该bean的`setMessageSource`方法,传入当前应用上下文的`MessageSource`实例。
|
||||
1. **自动注入**
|
||||
+ 当一个bean实现了`MessageSourceAware`接口,并且被Spring容器管理时,Spring将会自动调用该bean的`setMessageSource`方法,传入当前应用上下文的`MessageSource`实例。
|
||||
|
||||
**国际化支持**:通过`MessageSourceAware`,beans可以获得对`MessageSource`的访问权,从而可以根据不同的地区和语言获取相应的消息。这对于需要显示不同语言的错误消息、UI标签或其他用户面向的文本的beans特别有用。
|
||||
2. **国际化支持**
|
||||
+ 通过`MessageSourceAware`,beans可以获得对`MessageSource`的访问权,从而可以根据不同的地区和语言获取相应的消息。这对于需要显示不同语言的错误消息、UI标签或其他用户面向的文本的beans特别有用。
|
||||
|
||||
**简化配置**:虽然我们可以通过常规的依赖注入方法将`MessageSource`注入到beans中,但`MessageSourceAware`提供了一种更加自动化和明确的方法,特别是当我们的bean需要在初始化过程的特定阶段获得`MessageSource`时。
|
||||
3. **简化配置**
|
||||
+ 虽然我们可以通过常规的依赖注入方法将`MessageSource`注入到beans中,但`MessageSourceAware`提供了一种更加自动化和明确的方法,特别是当我们的bean需要在初始化过程的特定阶段获得`MessageSource`时。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyMessageSourceAware`类型的bean,最后调用`getMessage`方法。
|
||||
|
||||
|
@ -111,10 +120,10 @@ public class MyMessageSourceAware implements MessageSourceAware {
|
|||
|
||||
```java
|
||||
English:Hello!
|
||||
中文:你好
|
||||
中文:我们好
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -149,7 +158,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext-->>MessageSourceAwareApplication:初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyMessageSourceAware`类型的bean,最后调用`getMessage`方法。
|
||||
|
||||
|
@ -189,7 +198,7 @@ public void refresh() throws BeansException, IllegalStateException {
|
|||
}
|
||||
```
|
||||
|
||||
我们来到`org.springframework.context.support.AbstractApplicationContext#refresh`方法中的步骤1,在`org.springframework.context.support.AbstractApplicationContext#initMessageSource`方法中,这个方法确保Spring应用上下文总是有一个`MessageSource` bean可用,无论是否明确定义了它。如果用户没有定义,它会提供一个默认实现。这意味着在Spring上下文中,你总是可以安全地调用`getMessage()`,因为总会有一个`MessageSource`可用。
|
||||
我们来到`org.springframework.context.support.AbstractApplicationContext#refresh`方法中的步骤1,在`org.springframework.context.support.AbstractApplicationContext#initMessageSource`方法中,这个方法确保Spring应用上下文总是有一个`MessageSource` bean可用,无论是否明确定义了它。如果用户没有定义,它会提供一个默认实现。这意味着在Spring上下文中,我们总是可以安全地调用`getMessage()`,因为总会有一个`MessageSource`可用。
|
||||
|
||||
```java
|
||||
protected void initMessageSource() {
|
||||
|
@ -472,48 +481,67 @@ public class MyMessageSourceAware implements MessageSourceAware {
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**明确的配置**: 确保你的Spring上下文中有一个`MessageSource` bean,通常命名为“messageSource”。虽然Spring提供了一个默认的,但为了满足自定义需求,你可能需要明确地配置它。
|
||||
1. **明确的配置**
|
||||
+ 确保我们的Spring上下文中有一个`MessageSource` bean,通常命名为“messageSource”。虽然Spring提供了一个默认的,但为了满足自定义需求,我们可能需要明确地配置它。
|
||||
|
||||
**生命周期时机**: `MessageSourceAware`的`setMessageSource`方法在常规属性设置之后和初始化方法(如`InitializingBean`的`afterPropertiesSet`或任何自定义的init方法)之前被调用。确保你的bean不在其生命周期的早期阶段(例如,在构造函数中)期望使用`MessageSource`。
|
||||
2. **生命周期时机**
|
||||
+ `MessageSourceAware`的`setMessageSource`方法在常规属性设置之后和初始化方法(如`InitializingBean`的`afterPropertiesSet`或任何自定义的init方法)之前被调用。确保我们的bean不在其生命周期的早期阶段(例如,在构造函数中)期望使用`MessageSource`。
|
||||
|
||||
**文件位置和命名**: 如果你使用`ResourceBundleMessageSource`或类似的机制,确保你的属性文件位于类路径上,并且与你在`MessageSource`配置中指定的basename匹配。
|
||||
3. **文件位置和命名**
|
||||
+ 如果我们使用`ResourceBundleMessageSource`或类似的机制,确保我们的属性文件位于类路径上,并且与我们在`MessageSource`配置中指定的basename匹配。
|
||||
|
||||
**编码问题**: 属性文件默认使用ISO-8859-1编码。如果你的消息包含非此编码的字符(例如中文、俄文等),确保使用Unicode转义或正确设置文件的编码。
|
||||
4. **编码问题**
|
||||
+ 属性文件默认使用ISO-8859-1编码。如果我们的消息包含非此编码的字符(例如中文、俄文等),确保使用Unicode转义或正确设置文件的编码。
|
||||
|
||||
**父子上下文**: 在使用Spring的父子上下文(例如,在Web应用中)时,子上下文可以访问父上下文中的`MessageSource`,但反之则不行。确保你在正确的上下文中配置了`MessageSource`。
|
||||
5. **父子上下文**
|
||||
+ 在使用Spring的父子上下文(例如,在Web应用中)时,子上下文可以访问父上下文中的`MessageSource`,但反之则不行。确保我们在正确的上下文中配置了`MessageSource`。
|
||||
|
||||
**避免硬编码**: 尽量不要在代码中硬编码消息键或默认消息。最好在属性文件中管理它们,这样在未来需要更改或添加新的语言支持时,你不需要修改代码。
|
||||
6. **避免硬编码**
|
||||
+ 尽量不要在代码中硬编码消息键或默认消息。最好在属性文件中管理它们,这样在未来需要更改或添加新的语言支持时,我们不需要修改代码。
|
||||
|
||||
**默认消息**: 当使用`MessageSource`检索消息时,考虑提供一个默认消息。这可以在未找到特定消息时提供一个后备,避免抛出异常。
|
||||
7. **默认消息**
|
||||
+ 当使用`MessageSource`检索消息时,考虑提供一个默认消息。这可以在未找到特定消息时提供一个后备,避免抛出异常。
|
||||
|
||||
### 八、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**启动类**: 在`MessageSourceAwareApplication`类中,使用了`AnnotationConfigApplicationContext`来启动Spring应用。这个上下文是专为基于Java注解的配置而设计的。启动时,它加载了`MyConfiguration`配置类,并从上下文中获取了`MyMessageSourceAware`bean,随后调用了`getMessage`方法显示消息。
|
||||
1. **启动类**
|
||||
+ 在`MessageSourceAwareApplication`类中,使用了`AnnotationConfigApplicationContext`来启动Spring应用。这个上下文是专为基于Java注解的配置而设计的。启动时,它加载了`MyConfiguration`配置类,并从上下文中获取了`MyMessageSourceAware`bean,随后调用了`getMessage`方法显示消息。
|
||||
|
||||
**配置类**: `MyConfiguration`是一个基于Java的Spring配置类,其中定义了两个bean:`MyMessageSourceAware`和`messageSource`。`messageSource` bean是一个`ResourceBundleMessageSource`实例,用于从`i18n/messages`基本名称的属性文件中读取国际化消息。
|
||||
2. **配置类**
|
||||
+ `MyConfiguration`是一个基于Java的Spring配置类,其中定义了两个bean:`MyMessageSourceAware`和`messageSource`。`messageSource` bean是一个`ResourceBundleMessageSource`实例,用于从`i18n/messages`基本名称的属性文件中读取国际化消息。
|
||||
|
||||
**实现MessageSourceAware接口**: `MyMessageSourceAware`类实现了`MessageSourceAware`接口,这意味着Spring容器会自动注入一个`MessageSource`实例到这个bean中。这是通过`setMessageSource`方法完成的。
|
||||
3. **实现MessageSourceAware接口**
|
||||
+ `MyMessageSourceAware`类实现了`MessageSourceAware`接口,这意味着Spring容器会自动注入一个`MessageSource`实例到这个bean中。这是通过`setMessageSource`方法完成的。
|
||||
|
||||
**消息检索**: 在`MyMessageSourceAware`的`getMessage`方法中,使用了注入的`MessageSource`来检索和打印两种语言的国际化消息:英文和简体中文。
|
||||
4. **消息检索**
|
||||
+ 在`MyMessageSourceAware`的`getMessage`方法中,使用了注入的`MessageSource`来检索和打印两种语言的国际化消息:英文和简体中文。
|
||||
|
||||
**运行结果**: 当应用程序执行时,它成功地从对应的属性文件中获取并显示了英文和简体中文的国际化消息。
|
||||
5. **运行结果**
|
||||
+ 当应用程序执行时,它成功地从对应的属性文件中获取并显示了英文和简体中文的国际化消息。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**应用启动**:你从`MessageSourceAwareApplication`启动应用,使用`AnnotationConfigApplicationContext`初始化Spring容器,并加载`MyConfiguration`配置。
|
||||
1. **应用启动**
|
||||
+ 我们从`MessageSourceAwareApplication`启动应用,使用`AnnotationConfigApplicationContext`初始化Spring容器,并加载`MyConfiguration`配置。
|
||||
|
||||
**容器初始化**:在`AnnotationConfigApplicationContext`的构造函数中,执行了`register`和`refresh`方法,其中`refresh`是最重要的,它触发了容器的初始化和bean的创建过程。
|
||||
2. **容器初始化**
|
||||
+ 在`AnnotationConfigApplicationContext`的构造函数中,执行了`register`和`refresh`方法,其中`refresh`是最重要的,它触发了容器的初始化和bean的创建过程。
|
||||
|
||||
**消息源初始化**:在容器刷新的`refresh`方法中,首先确保了一个`MessageSource` bean存在,这是通过`initMessageSource`方法完成的。如果没有明确定义`MessageSource` bean,Spring会提供一个默认实现,确保应用上下文总是有一个可用。
|
||||
3. **消息源初始化**
|
||||
+ 在容器刷新的`refresh`方法中,首先确保了一个`MessageSource` bean存在,这是通过`initMessageSource`方法完成的。如果没有明确定义`MessageSource` bean,Spring会提供一个默认实现,确保应用上下文总是有一个可用。
|
||||
|
||||
**bean实例化**:随后,在`refresh`方法中,通过调用`finishBeanFactoryInitialization`方法,容器开始实例化所有非延迟加载的单例bean。
|
||||
4. **bean实例化**
|
||||
+ 随后,在`refresh`方法中,通过调用`finishBeanFactoryInitialization`方法,容器开始实例化所有非延迟加载的单例bean。
|
||||
|
||||
**Bean的生命周期**:在bean的创建过程中,Spring容器会确保所有的生命周期回调都被正确地执行,其中最重要的是`BeanPostProcessors`。这些处理器提供了一个插件机制,允许我们在bean的初始化前后执行自定义的逻辑。
|
||||
5. **Bean的生命周期**
|
||||
+ 在bean的创建过程中,Spring容器会确保所有的生命周期回调都被正确地执行,其中最重要的是`BeanPostProcessors`。这些处理器提供了一个插件机制,允许我们在bean的初始化前后执行自定义的逻辑。
|
||||
|
||||
**处理Aware接口**:`ApplicationContextAwareProcessor`是一个特殊的`BeanPostProcessor`,它关心那些实现了"Aware"接口的beans。对于实现了`MessageSourceAware`的beans,该处理器会自动注入应用上下文的`MessageSource`。
|
||||
6. **处理Aware接口**
|
||||
+ `ApplicationContextAwareProcessor`是一个特殊的`BeanPostProcessor`,它关心那些实现了"Aware"接口的beans。对于实现了`MessageSourceAware`的beans,该处理器会自动注入应用上下文的`MessageSource`。
|
||||
|
||||
**消息检索**:在你的`MyMessageSourceAware`类中,已经成功地获取了`MessageSource`的引用。然后,你调用其`getMessage`方法,从属性文件中检索并打印两个国际化的消息。
|
||||
7. **消息检索**
|
||||
+ 在我们的`MyMessageSourceAware`类中,已经成功地获取了`MessageSource`的引用。然后,我们调用其`getMessage`方法,从属性文件中检索并打印两个国际化的消息。
|
|
@ -1,24 +1,30 @@
|
|||
## ResourceLoaderAware
|
||||
|
||||
- [ResourceLoaderAware](#resourceloaderaware)
|
||||
- [一、接口描述](#一接口描述)
|
||||
- [二、接口源码](#二接口源码)
|
||||
- [三、主要功能](#三主要功能)
|
||||
- [四、最佳实践](#四最佳实践)
|
||||
- [五、时序图](#五时序图)
|
||||
- [六、源码分析](#六源码分析)
|
||||
- [七、注意事项](#七注意事项)
|
||||
- [八、总结](#八总结)
|
||||
- [8.1、最佳实践总结](#81最佳实践总结)
|
||||
- [8.2、源码分析总结](#82源码分析总结)
|
||||
- [一、基本信息](#一基本信息)
|
||||
- [二、接口描述](#二接口描述)
|
||||
- [三、接口源码](#三接口源码)
|
||||
- [四、主要功能](#四主要功能)
|
||||
- [五、最佳实践](#五最佳实践)
|
||||
- [六、时序图](#六时序图)
|
||||
- [七、源码分析](#七源码分析)
|
||||
- [八、注意事项](#八注意事项)
|
||||
- [九、总结](#九总结)
|
||||
- [最佳实践总结](#最佳实践总结)
|
||||
- [源码分析总结](#源码分析总结)
|
||||
|
||||
### 一、接口描述
|
||||
|
||||
### 一、基本信息
|
||||
|
||||
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133915709) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [ResourceLoaderAware源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-aware/spring-aware-resourceLoaderAware)
|
||||
|
||||
### 二、接口描述
|
||||
|
||||
`ResourceLoaderAware` 接口,它用于为需要访问 `ResourceLoader` 的 bean 提供一个回调。`ResourceLoader` 是一个简单的策略接口,定义了如何加载底层资源(如类路径或文件系统资源)的方法。
|
||||
|
||||
### 二、接口源码
|
||||
### 三、接口源码
|
||||
|
||||
`ResourceLoaderAware` 是 Spring 框架自 10.03.2004 开始引入的一个核心接口。主要是希望被通知并访问 `ResourceLoader` 的对象提供了一个机制。实现此接口的对象可以获取到 `ResourceLoader`,从而加载资源。
|
||||
`ResourceLoaderAware` 是 Spring 框架自 10.03.2004 开始引入的一个核心接口。实现`ResourceLoaderAware`接口的对象会在Spring容器中被自动注入一个`ResourceLoader`实例。
|
||||
|
||||
```java
|
||||
/**
|
||||
|
@ -28,7 +34,7 @@
|
|||
* 请注意,org.springframework.core.io.Resource 依赖也可以暴露为类型为 Resource 或 Resource[] 的bean属性,
|
||||
* 通过字符串在bean工厂中进行自动类型转换进行填充。这样就消除了为了访问特定文件资源而实现任何回调接口的需求。
|
||||
*
|
||||
* 当您的应用对象需要访问其名称经过计算的各种文件资源时,通常需要一个 ResourceLoader。
|
||||
* 当我们的应用对象需要访问其名称经过计算的各种文件资源时,通常需要一个 ResourceLoader。
|
||||
* 一个好策略是使对象使用 org.springframework.core.io.DefaultResourceLoader,但仍然实现 ResourceLoaderAware,
|
||||
* 以允许在 ApplicationContext 中运行时覆盖。参考 org.springframework.context.support.ReloadableResourceBundleMessageSource 为例。
|
||||
*
|
||||
|
@ -65,15 +71,18 @@ public interface ResourceLoaderAware extends Aware {
|
|||
}
|
||||
```
|
||||
|
||||
### 三、主要功能
|
||||
### 四、主要功能
|
||||
|
||||
**资源加载回调**:当 bean 实现了 `ResourceLoaderAware` 接口,Spring 容器会在该 bean 初始化时,自动将一个 `ResourceLoader` 注入到该 bean 中,从而使得 bean 可以加载资源。
|
||||
1. **资源加载回调**
|
||||
+ 当 bean 实现了 `ResourceLoaderAware` 接口,Spring 容器会在该 bean 初始化时,自动将一个 `ResourceLoader` 注入到该 bean 中,从而使得 bean 可以加载资源。
|
||||
|
||||
**提供资源加载策略**:通过 `ResourceLoader`, bean 可以加载各种类型的资源,如类路径资源、文件系统资源、URL 资源等。它为资源访问提供了一个统一的策略。
|
||||
2. **提供资源加载策略**
|
||||
+ 通过 `ResourceLoader`, bean 可以加载各种类型的资源,如类路径资源、文件系统资源、URL 资源等。它为资源访问提供了一个统一的策略。
|
||||
|
||||
**减少对 ApplicationContext 的直接依赖**:虽然 `ApplicationContext` 也扩展了 `ResourceLoader` 的功能,但有时候 bean 只需要资源加载功能,而不需要其他的 ApplicationContext 功能。通过实现 `ResourceLoaderAware`,bean 可以只获得资源加载功能,从而降低与完整的 `ApplicationContext` 的耦合。
|
||||
3. **减少对 ApplicationContext 的直接依赖**
|
||||
+ 虽然 `ApplicationContext` 也扩展了 `ResourceLoader` 的功能,但有时候 bean 只需要资源加载功能,而不需要其他的 ApplicationContext 功能。通过实现 `ResourceLoaderAware`,bean 可以只获得资源加载功能,从而降低与完整的 `ApplicationContext` 的耦合。
|
||||
|
||||
### 四、最佳实践
|
||||
### 五、最佳实践
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyResourceLoaderAware`类型的bean,最后调用`getResource`方法并传递了一个路径。
|
||||
|
||||
|
@ -130,7 +139,7 @@ public class MyResourceLoaderAware implements ResourceLoaderAware {
|
|||
Resource content: hello world
|
||||
```
|
||||
|
||||
### 五、时序图
|
||||
### 六、时序图
|
||||
|
||||
~~~mermaid
|
||||
sequenceDiagram
|
||||
|
@ -165,7 +174,7 @@ sequenceDiagram
|
|||
AnnotationConfigApplicationContext-->>ResourceLoaderAwareApplication:初始化完成
|
||||
~~~
|
||||
|
||||
### 六、源码分析
|
||||
### 七、源码分析
|
||||
|
||||
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`(此类是使用Java注解来配置Spring容器的方式),构造参数我们给定了一个`MyConfiguration`组件类。然后从Spring上下文中获取一个`MyResourceLoaderAware`类型的bean,最后调用`getResource`方法并传递了一个路径。
|
||||
|
||||
|
@ -456,50 +465,70 @@ public class MyResourceLoaderAware implements ResourceLoaderAware {
|
|||
}
|
||||
```
|
||||
|
||||
### 七、注意事项
|
||||
### 八、注意事项
|
||||
|
||||
**资源路径**:当使用 `ResourceLoader` 获取资源时,需要提供完整的路径。例如,使用 "classpath:" 前缀来加载类路径上的资源。你应确保路径是正确的,否则 `ResourceLoader` 可能找不到资源。
|
||||
1. **资源路径**
|
||||
+ 当使用 `ResourceLoader` 获取资源时,需要提供完整的路径。例如,使用 "classpath:" 前缀来加载类路径上的资源。我们应确保路径是正确的,否则 `ResourceLoader` 可能找不到资源。
|
||||
|
||||
**资源缓存**:`ResourceLoader` 本身不提供资源内容的缓存功能。每次调用 `getResource` 方法都可能返回一个新的 `Resource` 实例。如果需要缓存资源内容,你应该自己实现。
|
||||
2. **资源缓存**
|
||||
+ `ResourceLoader` 本身不提供资源内容的缓存功能。每次调用 `getResource` 方法都可能返回一个新的 `Resource` 实例。如果需要缓存资源内容,我们应该自己实现。
|
||||
|
||||
**资源存在性检查**:使用 `ResourceLoader` 获取的 `Resource` 不保证资源确实存在。在尝试访问资源内容之前,你应使用 `Resource.exists()` 方法检查资源是否存在。
|
||||
3. **资源存在性检查**
|
||||
+ 使用 `ResourceLoader` 获取的 `Resource` 不保证资源确实存在。在尝试访问资源内容之前,我们应使用 `Resource.exists()` 方法检查资源是否存在。
|
||||
|
||||
**资源类型的多样性**:根据运行环境和 `ResourceLoader` 的具体实现,它可以加载多种类型的资源,如类路径资源、文件系统资源、URL资源等。你应当了解当前环境支持的资源类型,并正确使用。
|
||||
4. **资源类型的多样性**
|
||||
+ 根据运行环境和 `ResourceLoader` 的具体实现,它可以加载多种类型的资源,如类路径资源、文件系统资源、URL资源等。我们应当了解当前环境支持的资源类型,并正确使用。
|
||||
|
||||
**避免过度使用**:虽然 `ResourceLoaderAware` 提供了一种方便的方式来访问资源,但不是所有的 beans 都需要它。只有当 bean 真正需要动态地加载资源时,才应实现这个接口。否则,更简洁的方式是直接注入 `Resource` 类型的属性。
|
||||
5. **避免过度使用**
|
||||
+ 虽然 `ResourceLoaderAware` 提供了一种方便的方式来访问资源,但不是所有的 beans 都需要它。只有当 bean 真正需要动态地加载资源时,才应实现这个接口。否则,更简洁的方式是直接注入 `Resource` 类型的属性。
|
||||
|
||||
**生命周期时机**:当一个 bean 实现了 `ResourceLoaderAware` 接口,`setResourceLoader` 方法会在 bean 初始化的早期被调用,这确保了后续的 bean 初始化和业务逻辑可以使用到 `ResourceLoader`。但你应确保不在构造函数中访问 `ResourceLoader`,因为它此时尚未被设置。
|
||||
6. **生命周期时机**
|
||||
+ 当一个 bean 实现了 `ResourceLoaderAware` 接口,`setResourceLoader` 方法会在 bean 初始化的早期被调用,这确保了后续的 bean 初始化和业务逻辑可以使用到 `ResourceLoader`。但我们应确保不在构造函数中访问 `ResourceLoader`,因为它此时尚未被设置。
|
||||
|
||||
**避免过度使用**:虽然 `ResourceLoaderAware` 提供了一种方便的方式来访问资源,但不是所有的 beans 都需要它。只有当 bean 真正需要动态地加载资源时,才应实现这个接口。否则,更简洁的方式是直接注入 `Resource` 类型的属性。
|
||||
7. **避免过度使用**
|
||||
+ 虽然 `ResourceLoaderAware` 提供了一种方便的方式来访问资源,但不是所有的 beans 都需要它。只有当 bean 真正需要动态地加载资源时,才应实现这个接口。否则,更简洁的方式是直接注入 `Resource` 类型的属性。
|
||||
|
||||
**与 `ApplicationContextAware` 的区别**:`ApplicationContext` 本身也是一个 `ResourceLoader`,因此实现 `ApplicationContextAware` 也可以获得类似的资源加载功能。但如果你的 bean 只需要资源加载功能,而不需要其他的 `ApplicationContext` 功能,那么最好只实现 `ResourceLoaderAware` 以减少耦合。
|
||||
8. **与 `ApplicationContextAware` 的区别**
|
||||
+ `ApplicationContext` 本身也是一个 `ResourceLoader`,因此实现 `ApplicationContextAware` 也可以获得类似的资源加载功能。但如果我们的 bean 只需要资源加载功能,而不需要其他的 `ApplicationContext` 功能,那么最好只实现 `ResourceLoaderAware` 以减少耦合。
|
||||
|
||||
### 八、总结
|
||||
### 九、总结
|
||||
|
||||
#### 8.1、最佳实践总结
|
||||
#### 最佳实践总结
|
||||
|
||||
**启动类入口**:使用了 `AnnotationConfigApplicationContext` 类来启动Spring应用。这是一个使用基于Java的注解来配置Spring容器的方式。上下文初始化时使用了 `MyConfiguration` 类作为配置类。接着,从Spring上下文中获取了一个 `MyResourceLoaderAware` 类型的bean。最后,调用了 `getResource` 方法并传入了一个指定的路径。
|
||||
1. **启动类入口**
|
||||
+ 使用了 `AnnotationConfigApplicationContext` 类来启动Spring应用。这是一个使用基于Java的注解来配置Spring容器的方式。上下文初始化时使用了 `MyConfiguration` 类作为配置类。接着,从Spring上下文中获取了一个 `MyResourceLoaderAware` 类型的bean。最后,调用了 `getResource` 方法并传入了一个指定的路径。
|
||||
|
||||
**配置类**:`MyConfiguration` 是一个标注有 `@Configuration` 的配置类,表示它是一个Spring配置类。在这个配置类中,通过 `@Bean` 注解定义了一个 `MyResourceLoaderAware` 类型的bean。这确保 `MyResourceLoaderAware` 被Spring容器管理,并且 `ResourceLoader` 被正确注入。
|
||||
2. **配置类**
|
||||
+ `MyConfiguration` 是一个标注有 `@Configuration` 的配置类,表示它是一个Spring配置类。在这个配置类中,通过 `@Bean` 注解定义了一个 `MyResourceLoaderAware` 类型的bean。这确保 `MyResourceLoaderAware` 被Spring容器管理,并且 `ResourceLoader` 被正确注入。
|
||||
|
||||
**资源加载实现**:`MyResourceLoaderAware` 类实现了 `ResourceLoaderAware` 接口,从而允许Spring容器在bean初始化时自动注入 `ResourceLoader`。`getResource` 方法使用注入的 `ResourceLoader` 来加载给定路径的资源,然后读取并打印资源的内容。
|
||||
3. **资源加载实现**
|
||||
+ `MyResourceLoaderAware` 类实现了 `ResourceLoaderAware` 接口,从而允许Spring容器在bean初始化时自动注入 `ResourceLoader`。`getResource` 方法使用注入的 `ResourceLoader` 来加载给定路径的资源,然后读取并打印资源的内容。
|
||||
|
||||
**运行结果**:当运行应用程序时,`MyResourceLoaderAware` 成功地从指定的资源路径加载内容,并将 "hello world" 打印到控制台。
|
||||
4. **运行结果**
|
||||
+ 当运行应用程序时,`MyResourceLoaderAware` 成功地从指定的资源路径加载内容,并将 "hello world" 打印到控制台。
|
||||
|
||||
#### 8.2、源码分析总结
|
||||
#### 源码分析总结
|
||||
|
||||
**启动与上下文初始化**:使用 `AnnotationConfigApplicationContext` 创建了一个基于Java注解的Spring容器,传入了 `MyConfiguration` 作为配置。从上下文中获取 `MyResourceLoaderAware` 类型的bean,并调用了其 `getResource` 方法。
|
||||
1. **启动与上下文初始化**
|
||||
+ 使用 `AnnotationConfigApplicationContext` 创建了一个基于Java注解的Spring容器,传入了 `MyConfiguration` 作为配置。从上下文中获取 `MyResourceLoaderAware` 类型的bean,并调用了其 `getResource` 方法。
|
||||
|
||||
**配置类与Bean注册**:在 `MyConfiguration` 配置类中,通过 `@Bean` 注解注册了 `MyResourceLoaderAware` 类型的bean。
|
||||
2. **配置类与Bean注册**
|
||||
+ 在 `MyConfiguration` 配置类中,通过 `@Bean` 注解注册了 `MyResourceLoaderAware` 类型的bean。
|
||||
|
||||
**上下文刷新与Bean实例化**:在上下文的 `refresh` 方法中,调用了 `finishBeanFactoryInitialization` 方法以实例化所有剩余的非懒加载单例Bean。在此方法中,调用了 `preInstantiateSingletons` 方法预先实例化所有非懒加载的单例bean。
|
||||
3. **上下文刷新与Bean实例化**
|
||||
+ 在上下文的 `refresh` 方法中,调用了 `finishBeanFactoryInitialization` 方法以实例化所有剩余的非懒加载单例Bean。在此方法中,调用了 `preInstantiateSingletons` 方法预先实例化所有非懒加载的单例bean。
|
||||
|
||||
**Bean获取与创建流程**:使用 `getBean` 方法来实际获取Bean,这可能会触发Bean的创建。在 `doGetBean` 方法中,如果bean还未创建,会尝试创建新实例,处理依赖关系,并返回正确的bean实例。
|
||||
4. **Bean获取与创建流程**
|
||||
+ 使用 `getBean` 方法来实际获取Bean,这可能会触发Bean的创建。在 `doGetBean` 方法中,如果bean还未创建,会尝试创建新实例,处理依赖关系,并返回正确的bean实例。
|
||||
|
||||
**单例Bean的创建与缓存**:在 `getSingleton` 方法中,首先尝试从单例缓存中获取bean实例。如果尚未创建,则使用提供的 `ObjectFactory` 创建新实例,并存入缓存。
|
||||
5. **单例Bean的创建与缓存**
|
||||
+ 在 `getSingleton` 方法中,首先尝试从单例缓存中获取bean实例。如果尚未创建,则使用提供的 `ObjectFactory` 创建新实例,并存入缓存。
|
||||
|
||||
**Bean初始化**:在Bean创建完成后,进行初始化。在 `initializeBean` 方法中,会对特定的bean应用 `BeanPostProcessor` 逻辑。
|
||||
6. **Bean初始化**
|
||||
+ 在Bean创建完成后,进行初始化。在 `initializeBean` 方法中,会对特定的bean应用 `BeanPostProcessor` 逻辑。
|
||||
|
||||
**Aware接口的处理**:使用 `ApplicationContextAwareProcessor` 处理实现了 `Aware` 接口的beans。对于实现了 `ResourceLoaderAware` 的beans,会注入一个 `ResourceLoader` 实例。
|
||||
7. **Aware接口的处理**
|
||||
+ 使用 `ApplicationContextAwareProcessor` 处理实现了 `Aware` 接口的beans。对于实现了 `ResourceLoaderAware` 的beans,会注入一个 `ResourceLoader` 实例。
|
||||
|
||||
**自定义逻辑**:在 `MyResourceLoaderAware` 类中,利用注入的 `ResourceLoader`,加载并打印资源内容。
|
||||
8. **自定义逻辑**
|
||||
+ 在 `MyResourceLoaderAware` 类中,利用注入的 `ResourceLoader`,加载并打印资源内容。
|
Loading…
Reference in New Issue