Spring 中的 initializeBean 方法小总结
背景
spring-beans 模块中的 AbstractAutowireCapableBeanFactory.java 文件里有 initializeBean 方法,这个方法会负责 bean 的 initialization(初始化),本文会对其主要逻辑进行总结。
正文
该方法的代码复制如下 ⬇️
/**
* Initialize the given bean instance, applying factory callbacks
* as well as init methods and bean post processors.
* <p>Called from {@link #createBean} for traditionally defined beans,
* and from {@link #initializeBean} for existing bean instances.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @return the initialized bean instance (potentially wrapped)
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
@SuppressWarnings("deprecation")
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// Skip initialization of a NullBean
if (bean.getClass() == NullBean.class) {
return bean;
}
invokeAwareMethods(beanName, bean);
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null), beanName, ex.getMessage(), ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
其中的主要逻辑共有 4 步,我把 4 个步骤的位置在下图中标出来了 ⬇️
从调用的方法的名称来看,除了第 1 步之外,其余的 3 步都和 init/initialization(初始化)有关,不妨就把第 2/3/4 步分别简称为 "前"/"中"/"后",而第一步则可以简称为"知"。于是可以把 4 个步骤概括如下 ⬇️
| 主要步骤 | 做了什么 | 核心代码 |
|---|---|---|
Step 1: 知 | 处理 3 个 BeanXXXAware 接口 | invokeAwareMethods(beanName, bean); |
Step 2: 前 | 在 Step 3 之前 调用各个 BeanPostProcessor 的 postProcessBeforeInitialization 方法 | wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); |
Step 3: 中 | 处理 InitializingBean 接口以及用户指定的 init method | invokeInitMethods(beanName, wrappedBean, mbd); |
Step 4: 后 | 在 Step 3 之后 调用各个 BeanPostProcessor 的 postProcessAfterInitialization 方法 | wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); |
Step 1: 知
invokeAwareMethods(String, Object) 方法的代码复制如下 ⬇️
private void invokeAwareMethods(String beanName, Object bean) {
if (bean instanceof Aware) {
if (bean instanceof BeanNameAware beanNameAware) {
beanNameAware.setBeanName(beanName);
}
if (bean instanceof BeanClassLoaderAware beanClassLoaderAware) {
ClassLoader bcl = getBeanClassLoader();
if (bcl != null) {
beanClassLoaderAware.setBeanClassLoader(bcl);
}
}
if (bean instanceof BeanFactoryAware beanFactoryAware) {
beanFactoryAware.setBeanFactory(AbstractAutowireCapableBeanFactory.this);
}
}
}
如果当前的 bean implement 了以下 3 个 BeanXXXAware 接口中的任意一个,在 invokeAwareMethods(String, Object) 方法中就会进行相应处理。
BeanXXXAware 接口 | 接口中定义了什么方法 | 例子 |
|---|---|---|
BeanNameAware | 假设一个 bean 需要感知自身的 beanName,我们可以让 implement BeanNameAware 接口,那么在 invokeAwareMethods(String, Object) 方法中就会用 来调用 setBeanName(String) 方法,从而将对应的 beanName 填进去 | |
BeanClassLoaderAware | 略 | |
BeanFactoryAware | 假设一个 bean 需要感知 BeanFactory,我们可以让 implement BeanFactoryAware 接口,那么在 invokeAwareMethods(String, Object) 方法中就会用 来调用 setBeanFactory(BeanFactory) 方法,从而将 BeanFactory 填进去 |
简要的类图如下 ⬇️(类图中把方法声明里所抛的异常省略了)
classDiagram
class Aware
<<interface>> Aware
Aware <|-- BeanNameAware
<<interface>> BeanNameAware
Aware <|-- BeanClassLoaderAware
<<interface>> BeanClassLoaderAware
Aware <|-- BeanFactoryAware
<<interface>> BeanFactoryAware
BeanNameAware: void setBeanName(String name)
BeanClassLoaderAware: void setBeanClassLoader(ClassLoader classLoader)
BeanFactoryAware: void setBeanFactory(BeanFactory beanFactory)
由于上方的类图中的接口所在包的包名普遍很长,我把这些接口的名称与对应的 fully qualified class name 的关系列在下表里了 ⬇️
| 接口名 | fully qualified class name |
|---|---|
Aware | org.springframework.beans.factory.Aware |
BeanNameAware | org.springframework.beans.factory.BeanNameAware |
BeanClassLoaderAware | org.springframework.beans.factory.BeanClassLoaderAware |
BeanFactoryAware | org.springframework.beans.factory.BeanFactoryAware |
Step 2: 前
applyBeanPostProcessorsBeforeInitialization(Object, String) 方法的代码复制如下 ⬇️
@Deprecated(since = "6.1")
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
这里的逻辑是遍历所有的 BeanPostProcessor,依次调用它们的 postProcessBeforeInitialization 方法(如果 postProcessBeforeInitialization 方法的返回值为 null,则提前结束)。
应用场景 1: @PostConstruct 的处理
我们平时用的 @PostConstruct 注解,它对应的 BeanPostProcessor 是 CommonAnnotationBeanPostProcessor。而对 @PostConstruct 的支持,就体现在 Step 2 里(可以在它的基类 InitDestroyAnnotationBeanPostProcessor 的 postProcessBeforeInitialization(Object bean, String beanName) 方法 打断点进行验证,这里就不展开说了)。
和 CommonAnnotationBeanPostProcessor 相关的简要类图如下 ⬇️ (请注意,图中略去了所有的泛型以及方法声明中的所有异常,也略去了一些与本文关系不大的类/接口/方法)
classDiagram
class PriorityOrdered
class Ordered
class InstantiationAwareBeanPostProcessor
class BeanPostProcessor
class DestructionAwareBeanPostProcessor
class MergedBeanDefinitionPostProcessor
<<interface>> PriorityOrdered
<<interface>> Ordered
<<interface>> InstantiationAwareBeanPostProcessor
<<interface>> BeanPostProcessor
<<interface>> DestructionAwareBeanPostProcessor
<<interface>> MergedBeanDefinitionPostProcessor
Ordered <|-- PriorityOrdered
DestructionAwareBeanPostProcessor <|.. InitDestroyAnnotationBeanPostProcessor
MergedBeanDefinitionPostProcessor <|.. InitDestroyAnnotationBeanPostProcessor
InstantiationAwareBeanPostProcessor <|.. CommonAnnotationBeanPostProcessor
PriorityOrdered <|.. InitDestroyAnnotationBeanPostProcessor
InitDestroyAnnotationBeanPostProcessor <|-- CommonAnnotationBeanPostProcessor
Ordered: getOrder()
BeanPostProcessor <|-- InstantiationAwareBeanPostProcessor
BeanPostProcessor <|-- DestructionAwareBeanPostProcessor
BeanPostProcessor <|-- MergedBeanDefinitionPostProcessor
InstantiationAwareBeanPostProcessor: postProcessBeforeInstantiation(Class, String)
InstantiationAwareBeanPostProcessor: postProcessAfterInstantiation(Object, String)
InstantiationAwareBeanPostProcessor: postProcessProperties(PropertyValues, Object, String)
BeanPostProcessor: postProcessBeforeInitialization(Object, String)
BeanPostProcessor: postProcessAfterInitialization(Object, String)
DestructionAwareBeanPostProcessor: postProcessBeforeDestruction(Object, String)
DestructionAwareBeanPostProcessor: boolean requiresDestruction(Object)
MergedBeanDefinitionPostProcessor: postProcessMergedBeanDefinition(RootBeanDefinition, Class, String)
MergedBeanDefinitionPostProcessor: resetBeanDefinition(String)
由于上方的类图中的类/接口所在包的包名普遍很长,我把这些类/接口的名称与对应的 fully qualified class name 的关系列在下表里了 ⬇️
| 类名/接口名 | fully qualified class name |
|---|---|
CommonAnnotationBeanPostProcessor | org.springframework.context.annotation.CommonAnnotationBeanPostProcessor |
InitDestroyAnnotationBeanPostProcessor | org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor |
PriorityOrdered | org.springframework.core.PriorityOrdered |
Ordered | org.springframework.core.Ordered |
InstantiationAwareBeanPostProcessor | org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor |
BeanPostProcessor | org.springframework.beans.factory.config.BeanPostProcessor |
DestructionAwareBeanPostProcessor | org.springframework.beans.factory.config.DestructionAwareBeanPostProcessor |
MergedBeanDefinitionPostProcessor | org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor |
应用场景 2: ApplicationContextAwareProcessor
在 AbstractApplicationContext.java 里的 prepareBeanFactory(...) 方法中,会添加 ApplicationContextAwareProcessor 这个 BeanPostProcessor ⬇️
在 ApplicationContextAwareProcessor 里,可以找到如下的代码 ⬇️
@Override
public @Nullable Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Aware) {
invokeAwareInterfaces(bean);
}
return bean;
}
private void invokeAwareInterfaces(Object bean) {
if (bean instanceof EnvironmentAware environmentAware) {
environmentAware.setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware embeddedValueResolverAware) {
embeddedValueResolverAware.setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware resourceLoaderAware) {
resourceLoaderAware.setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware applicationEventPublisherAware) {
applicationEventPublisherAware.setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware messageSourceAware) {
messageSourceAware.setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationStartupAware applicationStartupAware) {
applicationStartupAware.setApplicationStartup(this.applicationContext.getApplicationStartup());
}
if (bean instanceof ApplicationContextAware applicationContextAware) {
applicationContextAware.setApplicationContext(this.applicationContext);
}
}
上面的逻辑比较直观,如果当前 bean implement 以下 7 个 XXXAware 接口中的任何一个,那么这个接口上定义的 setXXX(...) 方法会被调用。
EnvironmentAwareEmbeddedValueResolverAwareResourceLoaderAwareApplicationEventPublisherAwareMessageSourceAwareApplicationStartupAwareApplicationContextAware
我画了简单的类图来展示这 7 个 XXXAware 接口和 Aware 接口之间的关系 ⬇️
classDiagram
class Aware
class EnvironmentAware
class EmbeddedValueResolverAware
class ResourceLoaderAware
class ApplicationEventPublisherAware
class MessageSourceAware
class ApplicationStartupAware
class ApplicationContextAware
<<interface>> Aware
<<interface>> EnvironmentAware
<<interface>> EmbeddedValueResolverAware
<<interface>> ResourceLoaderAware
<<interface>> ApplicationEventPublisherAware
<<interface>> MessageSourceAware
<<interface>> ApplicationStartupAware
<<interface>> ApplicationContextAware
Aware <|-- EnvironmentAware
Aware <|-- EmbeddedValueResolverAware
Aware <|-- ResourceLoaderAware
Aware <|-- ApplicationEventPublisherAware
Aware <|-- MessageSourceAware
Aware <|-- ApplicationStartupAware
Aware <|-- ApplicationContextAware
EnvironmentAware: setEnvironment(Environment)
EmbeddedValueResolverAware: setEmbeddedValueResolver(StringValueResolver)
ResourceLoaderAware: setResourceLoader(ResourceLoader)
ApplicationEventPublisherAware: setApplicationEventPublisher(ApplicationEventPublisher)
MessageSourceAware: setMessageSource(MessageSource)
ApplicationStartupAware: setApplicationStartup(ApplicationStartup)
ApplicationContextAware: setApplicationContext(ApplicationContext)
由于上方的类图中的接口所在包的包名普遍很长,我把这些接口的名称与对应的 fully qualified class name 的关系列在下表里了 ⬇️
| 接口名 | fully qualified class name |
|---|---|
Aware | org.springframework.beans.factory.Aware |
EnvironmentAware | org.springframework.context.EnvironmentAware |
EmbeddedValueResolverAware | org.springframework.context.EmbeddedValueResolverAware |
ResourceLoaderAware | org.springframework.context.ResourceLoaderAware |
ApplicationEventPublisherAware | org.springframework.context.ApplicationEventPublisherAware |
MessageSourceAware | org.springframework.context.MessageSourceAware |
ApplicationStartupAware | org.springframework.context.ApplicationStartupAware |
ApplicationContextAware | org.springframework.context.ApplicationContextAware |
Step 3: 中
invokeInitMethods(String, Object, RootBeanDefinition) 方法的代码复制如下 ⬇️
/**
* Give a bean a chance to initialize itself after all its properties are set,
* and a chance to know about its owning bean factory (this object).
* <p>This means checking whether the bean implements {@link InitializingBean}
* or defines any custom init methods, and invoking the necessary callback(s)
* if it does.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @throws Throwable if thrown by init methods or by the invocation process
* @see #invokeCustomInitMethod
*/
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.hasAnyExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
((InitializingBean) bean).afterPropertiesSet();
}
if (mbd != null && bean.getClass() != NullBean.class) {
String[] initMethodNames = mbd.getInitMethodNames();
if (initMethodNames != null) {
for (String initMethodName : initMethodNames) {
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd, initMethodName);
}
}
}
}
}
这个方法会处理以下 2 种情况
- 如果当前
beanimplement了InitializingBean接口,则尝试通过 来调用InitializingBean接口中的afterPropertiesSet()方法 - 如果当前
bean指定了init method(例如可以在xml文件里指定init method),则尝试通过 来调用这些init method
Step 4: 后
applyBeanPostProcessorsAfterInitialization(Object, String) 方法的代码复制如下 ⬇️
@Deprecated(since = "6.1")
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor processor : getBeanPostProcessors()) {
Object current = processor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
这一步和 Step 2 的代码类似,其逻辑是遍历所有的 BeanPostProcessor,依次调用它们的 postProcessAfterInitialization 方法 (如果 postProcessAfterInitialization 方法的返回值为 null,则提前结束)。
验证 4 个步骤
本文已经描述了 initializeBean 方法的 4 个步骤的主要逻辑。但是纸上得来终觉浅,我们还是写点代码验证一下。搭建一个完整的项目需要写不少代码,相信大家都有这方面的经验了,我只把核心的 java 代码以及 xml 文件的内容复制出来。
java 代码
请读者朋友在验证时,将以下 java 代码保存为 Main.java 并调整成合适的 package 语句。
package org.example.p0920;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.env.Environment;
public class Main {
public static void main(String[] args) {
new ClassPathXmlApplicationContext("simple-config.xml");
}
}
class MyBPP implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行时机: Step 4(由 MyBPP 处理)");
return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}
}
class SimpleBean implements
BeanNameAware, BeanClassLoaderAware, BeanFactoryAware,
EnvironmentAware, InitializingBean {
@Override
public void setBeanName(String name) {
System.out.println("执行时机: Step 1 中的第 1 步(Step 1 里共有 3 步)");
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("执行时机: Step 1 中的第 2 步(Step 1 里共有 3 步)");
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("执行时机: Step 1 中的第 3 步(Step 1 里共有 3 步)");
}
@Override
public void setEnvironment(Environment environment) {
// AutowiredAnnotationBeanPostProcessor 中会处理 7 个 XXXAware 接口,这里仅以 EnvironmentAware 作为示例,
// 另外 6 个就不赘述了
System.out.println("执行时机: Step 2(由 AutowiredAnnotationBeanPostProcessor 处理)");
}
@Override
public void afterPropertiesSet() {
System.out.println("执行时机: Step 3 中的第 1 步(对 InitializingBean 接口的处理)");
}
public void specifiedInitMethod() {
System.out.println("执行时机: Step 3 中的第 2 步(对 init method 的处理)");
}
}
xml 文件
xml 文件的内容如下 ⬇️
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd"
>
<bean id="simpleBean" class="org.example.p0920.SimpleBean" init-method="specifiedInitMethod"/>
<bean id="bpp" class="org.example.p0920.MyBPP"/>
</beans>
请将以上代码保存为 simple-config.xml(用其他文件名保存也没问题,但是请注意调整对应的 java 代码,具体位置如下 ⬇️)
另外,在您的电脑上,可以用其他的 package,但是请注意需要修改 xml 文件里对应的 package 名称(位置如下 ⬇️)
将代码准备好后,就可以运行 Main.java 中的 main(...) 方法了,相关的运行结果是 ⬇️
执行时机: Step 1 中的第 1 步(Step 1 里共有 3 步)
执行时机: Step 1 中的第 2 步(Step 1 里共有 3 步)
执行时机: Step 1 中的第 3 步(Step 1 里共有 3 步)
执行时机: Step 2(由 AutowiredAnnotationBeanPostProcessor 处理)
执行时机: Step 3 中的第 1 步(对 InitializingBean 接口的处理)
执行时机: Step 3 中的第 2 步(对 init method 的处理)
执行时机: Step 4(由 MyBPP 处理)
可见,initializeBean 方法的确是按照 "知"/"前"/"中"/"后" 4 个步骤来运转的。