Spring框架提供了丰富的扩展点,允许开发者在bean的生命周期的不同阶段插入自定义逻辑,从而增强应用的功能和灵活性。拓展点包括BeanFactoryPostProcessor
、BeanPostProcessor
、各种Aware等。下面来具体讲解各个拓展点的作用以及它们是如何介入到bean 的生命周期中。
除了Aware
接口和BeanPostProcessor
,还有许多其他扩展点,如BeanFactoryPostProcessor
、ApplicationListener
、InitializingBean
、FactoryBean
等。这些扩展点的合理使用可以极大地提高Spring应用的可扩展性和可维护性。
1.BeanFactoryPostProcessor
BeanFactoryPostProcessor
是 Spring 框架中的一个函数式接口,它在bean 开始整个创建流程之前 起作用。
通过实现该接口可以在 Bean 开始整个创建流程之前读取 BeanFactory
中的 BeanDefinition
并进行修改,比如调整 Bean 的属性、依赖关系等定义。
Spring 自带了一些 BeanFactoryPostProcessor
的实现,用户也可以根据需要自定义实现以适应特定场景,从而实现更灵活的应用配置。
1 |
|
1.1 注册时机 and 作用过程-invokeBeanFactoryPostProcessors
前面说到BeanFactoryPostProcessor
是 Spring 框架在bean 开始整个创建流程之前 起作用。具体的位置如下,位于refresh 中的invokeBeanFactoryPostProcessors 方法中, 通过invoke 这个命名就可以知道这里需要调用所有BeanFactoryPostProcessor
的具体实现逻辑对bean 定义进行修改
1 | AbstractApplicationContext.java |
执行BeanFactoryPostProcessor
逻辑前, 需要有BeanFactoryPostProcessor
的实例,那么BeanFactoryPostProcessor
是如何实例化的呢, 下面来看下 BeanFactoryPostProcessor
的实例化和具体起作用的过程
先进入1
2
3AbstractApplicationContext.java
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
}
再进入PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors的方法,可以看到此时传进来了3个BeanFactoryPostProcessor
,这3个BeanFactoryPostProcessor
是在应用上下文ApplicationContext 里面存储维护的,但是此时还没有看到自定义的
来看一下PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors 的具体处理逻辑.BeanFactoryPostProcessors将bean 分成了好几类分别进行处理,
1.2 BeanDefinitionRegistryPostProcessor
1 | public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor { |
BeanDefinitionRegistryPostProcessor 继承了BeanFactoryPostProcessor , 并增加了一个方法, 在执行BeanFactoryPostProcessor
前,需要找出所有的BeanDefinitionRegistryPostProcessor
, 并且先执行自己的postProcessBeanDefinitionRegistry
方法,再执行继承来的postProcessBeanFactory
方法。
看以下重点代码,BeanDefinitionRegistryPostProcessor
包括参数中传进来来的和从beanFactory 中找到的, 其中从beanFactory找到的BeanDefinitionRegistryPostProcessor,还没有进行实例化,需要实例化后才能使用,这个实例化的过程和业务bean 的实力化过程是同一个
1 | if (beanFactory instanceof BeanDefinitionRegistry) { |
1.3 执行顺序- Ordered
在invoke 完BeanDefinitionRegistryPostProcessor后,就开始按照优先级顺序处理BeanFactoryPostProcessor。
Spring提供了一些机制来管理多个BeanFactoryPostProcessor
的执行顺序,其执行顺序分别是
PriorityOrdered
接口- 优先级接口
Ordered
- NonOrdered
1.3.1 优先级接口 Ordered
Spring允许BeanFactoryPostProcessor
实现Ordered
接口来指定执行顺序。Ordered
接口要求实现一个方法getOrder()
,该方法返回一个整数,定义了BeanFactoryPostProcessor
的执行顺序。数值越小,优先级越高,越优先执行
例如,以下是一个BeanFactoryPostProcessor
实现,它使用了Ordered
接口来指定其执行顺序:
1 |
|
1.3.2 PriorityOrdered
接口
PriorityOrdered
是Ordered
接口的一个子接口,允许BeanFactoryPostProcessor
在其他普通Ordered
执行。这主要用于那些必须首先应用的处理器,比如那些涉及配置如何加载的处理器。1
2
3
4
5
6
7
8
9
10
11
12
13public class CustomPriorityOrderedBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 定制处理逻辑
System.out.println("Executing CustomPriorityOrderedBeanFactoryPostProcessor");
}
public int getOrder() {
return 5; // 数值越小,优先级越高
}
}
1.3.3 NonOrdered
NonOrdered并不是一个接口,指的是没有实现Ordered 或者 PriorityOrdered 的 BeanFactoryPostProcessor
, 它会放在最后执行。
所以,综上,在Spring容器启动过程中,BeanFactoryPostProcessor
的调用顺序如下:
- 首先,实现
PriorityOrdered
的BeanFactoryPostProcessor
按照它们的顺序值被调用。 - 其次,实现
Ordered
接口的普通BeanFactoryPostProcessor
按照它们的顺序值被调用。 - 最后,未实现任何排序接口的
BeanFactoryPostProcessor
按照它们的注册顺序被调用。
1.3.4 处理逻辑
在invoke 完BeanDefinitionRegistryPostProcessor后,就开始按照优先级顺序处理BeanFactoryPostProcessor
。 代码逻辑会先找出所有的BeanFactoryPostProcessor
, 然后将其分类为PriorityOrderedBeanFactoryPostProcessor
、OrderedBeanFactoryPostProcessor
、NonOrderedBeanFactoryPostProcessor
, 并按照优先级顺序分别invoke postProcessBeanFactory
方法
1 | public static void invokeBeanFactoryPostProcessors( |
1.4 BeanFactoryPostProcessor也是bean
无论是 BeanDefinitionRegistryPostProcessor
,还是BeanFactoryPostProcessor
, 在通过getBeanNamesForType
获取名称后,invoke postProcessBeanFactory
方法之前,需要先进行实例化操作(都要调用方法了,肯定要有对象存在啊)。 BeanFactoryPostProcessor 的实例化过程和业务bean 的实例化过程 完全相同,都是getBean流程完成实例化操作。
1 | // 实例化 BeanDefinitionRegistryPostProcessor |
2.BeanPostProcessor
BeanPostProcessor
是Spring框架中一个非常强大的扩展点,提供的一个接口,用于在bean的init操作前后执行自定义逻辑。Spring AOP就是通过BeanPostProcessor
实现的
BeanPostProcessor
也是一个接口,包含2个方法
- postProcessBeforeInitialization: 在bean init之前执行。
- postProcessAfterInitialization: 在bean init 之后执行。
1 | public interface BeanPostProcessor { |
2.1 注册时机-registerBeanPostProcessors
依然回到refresh
方法中 ,其中registerBeanPostProcessors
方法涉及到BeanPostProcessor
的注册流程。
1 | AbstractApplicationContext.java |
进入registerBeanPostProcessors
分析具体代码
1 |
|
可以看到registerBeanPostProcessors 的整理流程比较类似,都是
- 用beanFactory.getBeanNamesForType找出所有名字
- 分类
- getBean 实例化
一个比较明显的区别是 BeanFactoryPostProcessor
在实例化后会直接调用接口postProcessBeanFactory执行逻辑,但是BeanPostProcessor
的实例只会先添加到beanFactory 中,等到业务bean的init 阶段才会执行逻辑。
由此可见 注册BeanFactoryPostProcessor 用到的是invokeBeanFactoryPostProcessors
,BeanPostProcessor
只是registerBeanPostProcessors
, 这里的方法命名还是相当准确的
2.2 执行顺序-Ordered
从上面的代码中可以看到 Spring 管理多个BeanPostProcessor
的执行顺序,其实现和BeanFactoryPostProcessor
完全一致,
PriorityOrdered
接口- 优先级接口
Ordered
- NonOrdered
这里给出一些实际代码示例就不再赘述了。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
public class MyBeanPostProcessor implements BeanPostProcessor, Ordered {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 自定义逻辑
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 自定义逻辑
return bean;
}
public int getOrder() {
return 10; // 返回一个数值来指定执行顺序
}
}
public class PriorityLoggingBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// 在bean初始化之前打印日志
System.out.println("Before Initializing Bean '" + beanName + "': " + bean.getClass().getSimpleName());
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 初始化后的处理可以在这里添加,此示例仅在初始化前打印
return bean;
}
public int getOrder() {
// 返回值较低表示优先级较高,此处返回最高优先级
return PriorityOrdered.HIGHEST_PRECEDENCE;
}
}
2.3 BeanPostProcessor也是bean
通过registerBeanPostProcessors 代码可知, BeanPostProcessor
和Bean FactoryPostProcessor
一样, 通过getbean 进行实例化的1
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
并在实例化后添加到beanFactory 中进行管理1
2
3
4
5
6
7
8PostProcessorRegistrationDelegate.java
private static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
for (BeanPostProcessor postProcessor : postProcessors) {
beanFactory.addBeanPostProcessor(postProcessor);
}
}
2.4 Spring 启动过程中会用到的 BeanPostProcessor
2.4.1 InstantiationAwareBeanPostProcessor
图中置灰的2个方法,是继承自BeanPostProcessor的2个方法
InstantiationAwareBeanPostProcessor自有的3个方法中有2个方法名称和BeanPostProcessor中方式名称相同,但是入参和返回值略有不同
- postProcessBeforeInstantiation
1
2
3
4@Nullable
default Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
在bean 的实例化之前,会调用这个方法,其逻辑存在于下面代码中resolveBeforeInstantiation
方法中。 这个方法可以返回一个代理对象,来替代 Bean 的默认实例化过程。但通常情况下,代理对象是在 Bean 实例化之后创建的,所以这个方法一般返回 null
。
1 | @Override |
- postProcessAfterInstantiation
在 bean create之后,populate之前调用。返回true
表示允许属性注入,返回false
则跳过属性注入。
1 | default boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { |
- postProcessProperties
在populate 属性注入过程中调用,可以对属性值进行检查或修改。1
2
3
4
5@Nullable
default PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)
throws BeansException {
return null;
}
2.4.2 SmartInstantiationAwareBeanPostProcessor
SmartInstantiationAwareBeanPostProcessor
是 Spring 框架中的一个接口,它扩展了 InstantiationAwareBeanPostProcessor
接口,提供了更细粒度的控制和额外的钩子方法来介入 Spring Bean 的实例化过程。这个接口主要用于在 Bean create之前、create之后、populate之前、populate之后等多个阶段执行自定义逻辑,从而实现更加复杂和灵活的 Bean 初始化控制。
- predictBeanType
在实际创建 Bean 实例之前预测其类型。这对于提前检测某些类型相关的元数据很有用。1
2
3default Class<?> predictBeanType(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
determineCandidateConstructors
确定要用于创建 Bean 实例的候选构造函数。允许自定义选择用于实例化 Bean 的构造函数。1
2
3
4
5default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, String beanName)
throws BeansException {
return null;
}getEarlyBeanReference
允许在 Bean 实例化之前提前暴露 Bean 的引用。通常用于解决循环依赖问题1
2
3default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}
2.5 BeanFactoryPostProcessor vs BeanPostProcessor
BeanFactoryPostProcessor
和BeanPostProcessor
名称相似,但是作用大不相同,下面给出一些对比
为了更清楚地比较 BeanFactoryPostProcessor
和 BeanPostProcessor
,下表总结了它们的关键差异:
特征 | BeanFactoryPostProcessor | BeanPostProcessor |
---|---|---|
目的 | 修改或调整 bean 的配置元数据 | 在 bean 初始化前后对实例进行修改或增强 |
作用对象 | 操作 BeanDefinition (bean 的定义) |
直接操作 bean 实例 |
执行时机 | 在所有 bean 实例化前,容器启动过程中,加载完所有 bean 定义之后执行 | 对每个 bean,分别在初始化Initialization方法之前和之后执行 |
方法接口 | postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) |
postProcessBeforeInitialization(Object bean, String beanName) postProcessAfterInitialization(Object bean, String beanName) |
影响范围 | 可以修改整个容器中的所有 bean 定义 | 对每个 bean 实例的修改是独立的 |
应用示例 | 修改 bean 的作用域、解析配置文件中的占位符等 | 创建代理对象以实现 AOP,执行自定义初始化或清理代码等 |
执行顺序控制接口 | 通常可以通过实现 Ordered 或 PriorityOrdered 接口来控制执行顺序 |
同样可以实现 Ordered 或 PriorityOrdered 来控制执行顺序 |
3. 无所不知的Aware
Spring框架中,Aware
接口的作用是让bean能够拿到对Spring容器中的各种资源,从而增强bean的功能和灵活性。
不同的 Aware 基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware
可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在init阶段之前调用的
3.1 Aware调用时机
在Spring 启动过程中涉及到Aware ,都是在populate后,init 之前调用的。
其调用代码如下,
1 | protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { |
在Spring 中一些会用到Aware 列举如下, 这也是在实际运行中它们会被调用的顺序
- BeanNameAware: 最先被调用,用于设置bean的名称。
- BeanClassLoaderAware: 在bean实例化后,用于设置bean的类加载器。
- BeanFactoryAware: 在bean populate 完成后,用于设置bean的BeanFactory。
- EnvironmentAware: 在bean的populate 完成后,用于设置bean的环境信息。
- EmbeddedValueResolverAware: 在bean的populate 完成后,用于设置Spring EL解析器。
- ApplicationContextAware: 最后被调用,用于设置bean的ApplicationContext。
下面将分组进行解释
3.2 Aware Group 1- Bean 相关Aware
在invokeAwareMethods方法中,会调用以下3个Aware
- BeanNameAware: 用于让bean获取其在容器中的名称。在实例化之后,设置依赖之前被调用。
- BeanClassLoaderAware: 用于让bean获取类加载器。这通常在bean实例化之后和依赖注入之前被调用。
- BeanFactoryAware: 用于让bean获取它所在的BeanFactory实例。在依赖注入之后,bean初始化之前被调用。
点击查看invokeAwareMethods, 其逻辑涉及到3个Aware 接口
1.BeanFactoryAware
1 | public interface BeanFactoryAware { |
- 作用:允许bean获取
BeanFactory
实例,从而能够访问Spring容器中的其他bean。 - 使用场景:在需要动态获取或创建bean的场景下使用,例如实现复杂的依赖关系或自定义初始化逻辑。
2.BeanNameAware
1 | public interface BeanNameAware { |
实现 BeanNameAware
接口的 bean 会在 Spring 容器创建并初始化该 bean 时,调用 setBeanName
方法,将容器中为该 bean 配置的名称传递给它。这对于需要知道自己在容器中的名称的 bean 来说非常有用。
3.3 Aware Group 2-ApplicationContext 相关Aware
并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的
- EnvironmentAware: 允许bean访问Spring的Environment接口,用于获取环境属性和配置文件信息。
- EmbeddedValueResolverAware: 允许bean获取Spring的字符串值解析器,特别是用来解析Spring EL表达式(SpEL)。
- ApplicationContextAware: 允许bean获取ApplicationContext,这是BeanFactory的一个子接口,提供更多容器功能和应用上下文相关的信息。
跟进代码最后来到ApplicationContextAwareProcessor中,ApplicationContextAwareProcessor 是一个BeanPostProcessor, 最后在其重写的postProcessBeforeInitialization方法中,会调用如下方法。
3.4 Aware执行时机
1 | protected Object initializeBean(String beanName, Object bean, { RootBeanDefinition mbd) |
示例代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;
public class MyBeanFactoryAwareBean implements BeanFactoryAware {
private BeanFactory beanFactory;
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
System.out.println("BeanFactory has been set: " + beanFactory);
}
public void doSomething() {
// 使用beanFactory获取另一个bean
MyOtherBean otherBean = beanFactory.getBean(MyOtherBean.class);
otherBean.performTask();
}
}
4.Bean生命周期
对bean 的生命周期做细化的话可以分为以下阶段
实例化(Instantiation):
- Spring容器使用构造函数或工厂方法实例化bean。
属性填充(Dependency Injection):
- Spring容器进行依赖注入,将所有需要的属性和依赖注入到bean实例中。
设置特殊回调接口(Aware接口):
- 如果bean实现了
Aware
接口,Spring容器会在这个阶段调用相应的方法。 - 包括
BeanNameAware
、BeanClassLoaderAware
、BeanFactoryAware
等。
- 如果bean实现了
初始化前处理(BeanPostProcessor的
postProcessBeforeInitialization
方法):- Spring容器会在这个阶段调用所有注册的
BeanPostProcessor
的postProcessBeforeInitialization
方法。
- Spring容器会在这个阶段调用所有注册的
初始化(Initialization):
- 如果bean实现了
InitializingBean
接口,Spring容器会调用其afterPropertiesSet
方法。 - 如果bean配置了自定义的init方法,Spring容器会调用该方法。
- 如果bean实现了
初始化后处理(BeanPostProcessor的
postProcessAfterInitialization
方法):- Spring容器会在这个阶段调用所有注册的
BeanPostProcessor
的postProcessAfterInitialization
方法。
- Spring容器会在这个阶段调用所有注册的