Spring对Bean生命周期的管理不仅有效地管理了Bean之间的依赖关系,还为开发者提供了丰富的扩展点。本文将从Spring容器启动开始,从储存Bean定义到注册销毁Bean,完整地梳理Bean的生命周期,深入体会Bean实例创建的灵活性与可靠性。
pre: Spring 如何知道要创建哪些 Bean 呢?
在Spring容器启动后,启动 loadBeanDefinitions()
方法,通过配置文件、注解扫描等方式找到程序员在代码中定义的Bean类,将Bean的定义信息注册到spring容器中。
Spring会将这些类定义信息转换为 BeanDefinition
对象并存储到 BeanDefinitionRegistry
中。
有了需要生成的bean定义的集合,后续就可以遍历这个集合,用类定义信息逐个调用 doCreateBean() 方法创建Bean。
⚠️注意:BeanFactoryPostProcessor
Bean工厂后处理器 就是在 BeanDefinitionMap
填充完毕,Bean实例化之前执行的。可以让开发者对BeanDefinition进行动态修改。
创建 Bean 的流程
创建Bean的流程大致分为四个阶段:
- 对象实例化
- 属性填充
- 实例初始化
- 注册销毁
在方法doCreateBean()
中很清晰的依次执行了这四个步骤
// AbstractAutowireCapableBeanFactory.java 简化版
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// 1. 对象实例化
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
//
Object exposedObject = bean;
try {
// 2. 属性填充
populateBean(beanName, mbd, instanceWrapper);
// 3. 实例初始化
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 4. 注册销毁回调接口
try {
this.registerDisposableBeanIfNecessary(beanName, bean, mbd);
return exposedObject;
}
}
下面对这四个阶段逐一介绍:
1 对象实例化 / 构造对象
通过调用 createBeanInstance()
,进行Bean实例构造。
a 利用反射机制从Bean定义中拿到该类的构造方法。具体拿哪个构造方法的规则:
- 有多个构造方法时,拿加了
@Autowired
的构造方法; - 如果有多个构造方法加了
@Autowired
注解,不能判断报错; - 如果都没加注解,优先拿无入参的方法,全部都有入参,spring回根据参数的类型来尝试匹配。
b 在调用构造方法时,Spring会根据参数的类型在容器中查找对应的依赖,支持基于类型或名称的依赖查找,必要时使用@Qualifier等注解进行细化。
c 有了构造函数和对应入参,通过反射进行Bean的构造
用类中唯一的构造方法来进行Bean的注入的优势也体现在这里: 明确的依赖关系
使用类中唯一的构造方法进行Bean注入,可以确保依赖关系在实例化时明确无误。构造函数的参数直接表明了该类所依赖的其他Bean,这种强制性有助于防止依赖未被满足的情况。
2 属性填充
通过调用 populateBean()
,对Bean内部需要的属性进行填充,通常来说就是加了@Autowired
注解的变量。通过三级缓存机制进行填充,从而避免循环依赖。
3 实例初始化
经过对象实例化和属性填充后,Bean的依赖已经被解析并注入,但此时Bean还没有完成其全部的初始化过程,因此还不具备Spring要求的完整生命周期特性,不能被直接添加到单例池中。
这一部分的目的是确保Bean在spring容器中被完全初始化,准备好在应用程序中使用,同时运行开发者对Bean进行功能扩展。调用 initializeBean()
来完成。具体来说,可以分为下面几部分:
1 检查 Aware 相关接口并设置相关依赖(容器信息);
2 执行BeanPostProcessor类后处理器中设置的前置类后处理器方法(如果有的话);
类后处理器是Spring提供的重要扩展点,允许用户介入到Bean的实例化流程中。
3 调用invokeInitMethods()
,若 Bean 实现了 InitializingBean 接口,调用 afterPropertiesSet()
方法
4 执行自定义的初始化方法 init-method()
;
5 执行BeanPostProcessor类后处理器中设置的后置类后处理器方法(如果有的话);
到这里为止,就已经完成了Bean实例的完全初始化,可以被正常使用了。
4 注册销毁
为了确保Bean实例能够被优雅地销毁,在将Bean放入单例池之前,会调用 registerDisposableBeanIfNecessary()
方法注册实现了 DisposableBean 接口的Bean。这样,在需要销毁该Bean时,可以调用其 destroy()
方法来实现销毁逻辑。
通过这几个步骤,完整的Bean就被创建并准备好使用。最后,通过 addSingleton()
方法将这个Bean添加到单例池中,以便后续使用管理。