优化BeanFactoryPostProcessor

master
xuchengsheng 2023-10-15 17:24:32 +08:00
parent c43c9c921e
commit ecc2b52f29
1 changed files with 63 additions and 38 deletions

View File

@ -1,23 +1,28 @@
## BeanFactoryPostProcessor
- [BeanFactoryPostProcessor](#beanfactorypostprocessor)
- [一、接口描述](#一接口描述)
- [二、接口源码](#二接口源码)
- [三、主要功能](#三主要功能)
- [四、最佳实践](#四最佳实践)
- [五、时序图](#五时序图)
- [六、源码分析](#六源码分析)
- [七、注意事项](#七注意事项)
- [八、总结](#八总结)
- [8.1、最佳实践总结](#81最佳实践总结)
- [8.2、源码分析总结](#82源码分析总结)
- [一、基本信息](#一基本信息)
- [二、接口描述](#二接口描述)
- [三、接口源码](#三接口源码)
- [四、主要功能](#四主要功能)
- [五、最佳实践](#五最佳实践)
- [六、时序图](#六时序图)
- [七、源码分析](#七源码分析)
- [八、注意事项](#八注意事项)
- [九、总结](#九总结)
- [最佳实践总结](#最佳实践总结)
- [源码分析总结](#源码分析总结)
### 一、接口描述
### 一、基本信息
✒️ **作者** - Lex 📝 **博客** - [我的CSDN](https://blog.csdn.net/duzhuang2399/article/details/133844965) 📚 **文章目录** - [所有文章](https://github.com/xuchengsheng/spring-reading) 🔗 **源码地址** - [BeanFactoryPostProcessor源码](https://github.com/xuchengsheng/spring-reading/tree/master/spring-interface/spring-interface-beanFactoryPostProcessor)
### 二、接口描述
`BeanFactoryPostProcessor` 是一个接口,任何实现此接口的类都必须提供`postProcessBeanFactory`方法的实现。此方法提供了一个机会在bean实例化之前修改bean的定义。
### 二、接口源码
### 、接口源码
`BeanFactoryPostProcessor` 是 Spring 框架自 06.07.2003 开始引入的一个核心接口。此接口提供了一个强大的方式来修改bean的属性和依赖关系使得我们可以根据特定的配置或环境条件动态地调整这些值。
@ -48,14 +53,21 @@ public interface BeanFactoryPostProcessor {
}
```
### 、主要功能
### 、主要功能
+ **修改Bean定义**在Spring加载所有bean定义后但在它开始实例化这些bean之前`BeanFactoryPostProcessor`会被调用。这意味着我们可以使用它来修改这些bean定义。
+ **更改属性值**你可以更改bean的属性或依赖这在某些场景下如需要根据环境或其他外部因素动态地配置bean时会非常有用。
+ **添加或删除Bean定义**不仅可以修改现有的bean定义还可以添加新的bean定义或删除现有的bean定义。
+ **应用多个BeanFactoryPostProcessors**:如果有多个`BeanFactoryPostProcessor`,你可以通过实现`Ordered`接口来控制它们的执行顺序。
1. **修改Bean定义**
+ 在Spring加载所有bean定义后但在它开始实例化这些bean之前`BeanFactoryPostProcessor`会被调用。这意味着我们可以使用它来修改这些bean定义。
### 四、最佳实践
2. **更改属性值**
+ 我们可以更改bean的属性或依赖这在某些场景下如需要根据环境或其他外部因素动态地配置bean时会非常有用。
3. **添加或删除Bean定义**
+ 不仅可以修改现有的bean定义还可以添加新的bean定义或删除现有的bean定义。
4. **应用多个BeanFactoryPostProcessors**
+ 如果有多个`BeanFactoryPostProcessor`,我们可以通过实现`Ordered`接口来控制它们的执行顺序。
### 五、最佳实践
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类。然后我们会调用`mySimpleBean1`和`mySimpleBean2`中的`show()`方法,我们可以判断`MySimpleBean`的作用域是单例还是原型。如果它们指向同一个实例,那么它是单例的;否则,它是原型的。
@ -103,7 +115,7 @@ public class MySimpleBean {
}
```
这个 `MyBeanFactoryPostProcessor` 类是一个简单的 `BeanFactoryPostProcessor` 的实现,它在被调用时,会从`beanFactory`工厂中获取名为`mySimpleBean`的bean定义默认情况下所有的bean都是单例的然后将`mySimpleBean`的作用域从单例改为原型。在实际应用中,可能会在 `postProcessBeanFactory` 方法内部执行更复杂的操作,例如修改 bean 的属性、对Bean对象进行代理做功能增强处理、更改它们的作用域或添加新的 bean 定义等。
这个 `MyBeanFactoryPostProcessor` 类是一个简单的 `BeanFactoryPostProcessor` 的实现,它在被调用时,会从`beanFactory`工厂中获取名为`mySimpleBean`的bean定义默认情况下所有的bean都是单例的然后将`mySimpleBean`的作用域从单例改为原型。在实际应用中,我们可能会在 `postProcessBeanFactory` 方法内部执行更复杂的操作,例如修改 bean 的属性、对Bean对象进行代理做功能增强处理、更改它们的作用域或添加新的 bean 定义等。
```java
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@ -129,7 +141,7 @@ MySimpleBean instance: com.xcs.spring.config.MySimpleBean@11392934
MySimpleBean instance: com.xcs.spring.config.MySimpleBean@6892b3b6
```
### 、时序图
### 、时序图
```mermaid
sequenceDiagram
@ -153,7 +165,7 @@ sequenceDiagram
AnnotationConfigApplicationContext->>BeanFactoryPostProcessorApplication:初始化完成
```
### 、源码分析
### 、源码分析
首先来看看启动类入口,上下文环境使用`AnnotationConfigApplicationContext`此类是使用Java注解来配置Spring容器的方式构造参数我们给定了一个`MyConfiguration`组件类。从Spring上下文中获取MySimpleBean的两个实例调用这两个实例的show方法如果MySimpleBean是单例的那么这两个实例应该是同一个对象反之则不是。
@ -316,36 +328,49 @@ public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
}
```
### 、注意事项
### 、注意事项
**考虑其他的`BeanFactoryPostProcessor`**:在大型应用程序中,可能存在多个`BeanFactoryPostProcessor`。你需要确保它们不会互相冲突或导致不一致的bean定义。
1. **考虑其他的`BeanFactoryPostProcessor`**
+ 在大型应用程序中,可能存在多个`BeanFactoryPostProcessor`。我们需要确保它们不会互相冲突或导致不一致的bean定义。
**注意执行顺序**:如果有多个`BeanFactoryPostProcessor`,它们的执行顺序可能会影响结果。使用`Ordered`接口或`PriorityOrdered`接口来明确设置执行顺序。
2. **注意执行顺序**
+ 如果有多个`BeanFactoryPostProcessor`,它们的执行顺序可能会影响结果。使用`Ordered`接口或`PriorityOrdered`接口来明确设置执行顺序。
**避免循环依赖**修改bean定义可能会引入循环依赖。确保你充分理解bean之间的依赖关系并尝试避免修改这些关系。比如当你修改了`BeanDefinition`构造函数,等等情况都有可能引入循环依赖。
3. **避免循环依赖**
+ 修改bean定义可能会引入循环依赖。确保我们充分理解bean之间的依赖关系并尝试避免修改这些关系。比如当我们修改了`BeanDefinition`构造函数,等等情况都有可能引入循环依赖。
**不要过度使用**:虽然`BeanFactoryPostProcessor`是一个非常强大接口,但这并不意味着我们就应该频繁使用它。只在真正需要的时候使用它,并考虑是否有其他更简单、更直观的方法可以达到同样的目的。
4. **不要过度使用**
+ 虽然`BeanFactoryPostProcessor`是一个非常强大接口,但这并不意味着我们就应该频繁使用它。只在真正需要的时候使用它,并考虑是否有其他更简单、更直观的方法可以达到同样的目的。
**谨慎使用**:虽然`BeanFactoryPostProcessor`是一个非常强大接口允许你修改bean的定义。这意味着你可以更改bean的类、作用域、属性等。我们要在做这些更改时要非常小心想想为什么要修改影响的范围有多少以免引入不一致或不可预测的行为。
5. **谨慎使用**
+ 虽然`BeanFactoryPostProcessor`是一个非常强大接口允许我们修改bean的定义。这意味着我们可以更改bean的类、作用域、属性等。我们要在做这些更改时要非常小心想想为什么要修改影响的范围有多少以免引入不一致或不可预测的行为。
### 、总结
### 、总结
#### 8.1、最佳实践总结
#### 最佳实践总结
**初始化与配置**:使用`AnnotationConfigApplicationContext`, 我们成功地启动了Spring容器并加载了`MyConfiguration`配置。在`MyConfiguration`中, 我们定义了两个核心bean`MySimpleBean`和`MyBeanFactoryPostProcessor`.
1. **初始化与配置**
+ 使用`AnnotationConfigApplicationContext`, 我们成功地启动了Spring容器并加载了`MyConfiguration`配置。在`MyConfiguration`中, 我们定义了两个核心bean`MySimpleBean`和`MyBeanFactoryPostProcessor`.
**修改Bean的作用域**:虽然`MySimpleBean`默认是单例,但通过`MyBeanFactoryPostProcessor`,我们改变了这一默认行为,将其转变为原型作用域。这种转变是通过覆盖`postProcessBeanFactory`方法并更改`mySimpleBean`的bean定义来完成的。
2. **修改Bean的作用域**
+ 虽然`MySimpleBean`默认是单例,但通过`MyBeanFactoryPostProcessor`,我们改变了这一默认行为,将其转变为原型作用域。这种转变是通过覆盖`postProcessBeanFactory`方法并更改`mySimpleBean`的bean定义来完成的。
**验证修改**:当我们从主应用程序获取`MySimpleBean`的两个实例并调用它们的`show`方法时输出的实例地址明确地告诉我们这两个bean是不同的实例。
3. **验证修改**
+ 当我们从主应用程序获取`MySimpleBean`的两个实例并调用它们的`show`方法时输出的实例地址明确地告诉我们这两个bean是不同的实例。
#### 8.2、源码分析总结
#### 源码分析总结
**启动与上下文**:利用 `AnnotationConfigApplicationContext`我们初始化了Spring容器并加载了`MyConfiguration`作为主要配置。
1. **启动与上下文**
+ 利用 `AnnotationConfigApplicationContext`我们初始化了Spring容器并加载了`MyConfiguration`作为主要配置。
**核心调用**Spring容器的`refresh`方法中,`invokeBeanFactoryPostProcessors(beanFactory)`确保所有的`BeanFactoryPostProcessor`得到适当的调用。
2. **核心调用**
+ Spring容器的`refresh`方法中,`invokeBeanFactoryPostProcessors(beanFactory)`确保所有的`BeanFactoryPostProcessor`得到适当的调用。
**回调顺序**在Spring中实现了`BeanFactoryPostProcessor`接口的bean不是随机调用的。Spring确保它们按照`PriorityOrdered`、`Ordered`和无顺序的层次结构进行分类和调用。
3. **回调顺序**
+ 在Spring中实现了`BeanFactoryPostProcessor`接口的bean不是随机调用的。Spring确保它们按照`PriorityOrdered`、`Ordered`和无顺序的层次结构进行分类和调用。
**自定义逻辑**:当我们实现`BeanFactoryPostProcessor`接口并提供自定义逻辑时例如更改Bean的作用域该逻辑将在上述过程的适当阶段被调用。
4. **自定义逻辑**
+ 当我们实现`BeanFactoryPostProcessor`接口并提供自定义逻辑时例如更改Bean的作用域该逻辑将在上述过程的适当阶段被调用。
**具体实践**:通过具体示例,我们查看了如何利用`BeanFactoryPostProcessor`在bean实例化前更改bean定义。在我们的例子中`MySimpleBean`的作用域从单例被更改为原型。
5. **具体实践**
+ 通过具体示例,我们查看了如何利用`BeanFactoryPostProcessor`在bean实例化前更改bean定义。在我们的例子中`MySimpleBean`的作用域从单例被更改为原型。