贯通
2023年7月25日大约 2 分钟约 741 字
Bean 的创建过程
从代码看 Spring 对于 Bean 的生成过程,步骤还是很多的,我把一些扩展业务代码省略掉,先上点开胃菜:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
// Bean 初始化第一步:默认调用无参构造实例化 Bean
// 如果是只有带参数的构造方法,构造方法里的参数依赖注入,就是发生在这一步
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// Initialize the Bean instance.
Object exposedObject = Bean;
try {
// Bean 创建第二步:填充属性(DI 依赖注入发生在此步骤)
populateBean(beanName, mbd, instanceWrapper);
// Bean 创建第三步:调用初始化方法,完成 Bean 的初始化操作(AOP 的第三个入口)
// AOP 是通过自动代理创建器 AbstractAutoProxyCreator 的 postProcessAfterInitialization()
// 方法的执行进行代理对象的创建的,AbstractAutoProxyCreator 是 BeanPostProcessor 接口的实现
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
// ...
}
// ...
从上述代码看出,整体脉络可以归纳成 3 个核心步骤:
- 实例化 Bean:主要是通过反射调用默认构造函数创建 Bean 实例,此时 Bean 的属性都还是默认值
null
。被注解@Bean
标注的方法就是此阶段被调用的。 - 填充 Bean 属性:这一步主要是对 Bean 的依赖属性进行填充,对
@Value
、@Autowired
、@Resource
注解标注的属性注入对象引用。 - 调用 Bean 初始化方法:调用配置指定中的
init
方法,如 xml 文件指定 Bean 的init-method
方法或注解@Bean(initMethod = "initMethod")
指定的方法。
在 Bean 创建的流程中 Spring 提供了多个BeanPostProcessor
接口(下称BPP
)方便开发者对 Bean 进行自定义调整和加工。有以下几种 BPP 接口比较常用:
postProcessMergedBeanDefinition
:可对BeanDefinition
添加额外的自定义配置getEarlyBeanReference
:返回早期暴露的 Bean 引用,一个典型的例子是循环依赖时如果有动态代理,需要在此先返回代理实例postProcessAfterInstantiation
:在 populateBean 前用户可以手动注入一些属性postProcessProperties
:对属性进行注入,例如配置文件加密信息在此解密后注入postProcessBeforeInitialization
:属性注入后的一些额外操作postProcessAfterInitialization
:实例完成创建的最后一步,这里也是一些 BPP 进行 AOP 代理的时机。 最后,对 Bean 的生命流程进行一个流程图的总结:

此处敲黑板划重点:Spring 的动态代理(AOP)是通过 BPP 实现的(在图中的 3.4 步实现),其中
AbstractAutoProxyCreator
是十分典型的自动代理类,它实现了SmartInstantiationAwareBeanPostProcessor
接口,并重写了getEarlyBeanReference
和postProcessAfterInitialization
两个方法实现代理的逻辑,这样完成对原始 Bean 进行增强,生成新 Bean 对象,将增强后的新 Bean 对象注入到属性依赖中。