SpringBean 的生命周期以及如何解决循环引用
共计 1388 个字符,预计需要花费 4 分钟才能阅读完成。
1. SpringBean的生命周期
Spring Bean 的生命周期从 Bean 实例化开始,即通过反射创建对象,到 Bean 成为一个完整的对象,最终存储到单例池中。整个过程被称为 Spring Bean 的生命周期,大致分为三个阶段。
第一阶段是 Bean 的实例化。Spring 框架根据 BeanDefinition 的信息判断 Bean 的范围是否是 singleton,是否延迟加载,是否为 FactoryBean 等。最终,通过反射实例化一个普通的 singleton Bean。
第二阶段是 Bean 的初始化。在 Bean 创建之后,它仍然是一个"半成品",需要对 Bean 实例的属性进行填充,执行一些 Aware 接口方法,执行 BeanPostProcessor 的方法,执行 InitializingBean 接口的初始化方法,以及执行自定义的初始化方法。这个阶段是 Spring 中最具技术含量和复杂度的阶段,包括 AOP 增强功能和后续要学习的 Spring 注解功能。同时,这个阶段也是解决 Spring Bean 循环引用问题的关键。
第三阶段是 Bean 的完成。经过初始化阶段,Bean 成为一个完整的 Spring Bean,并被存储到单例池中,即完成了整个 Spring Bean 的生命周期。
2. 循环依赖的解决
以下为 spring 的三级缓存源码:
public class DefaultSingletonBeanRegistry ... {
// 1. 存储已完成初始化的单例Bean的容器,即存储实例化和初始化都完成的Bean,称为一级缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap(256);
// 2. 存储早期Bean单例的缓存,即存储半成品对象,且当前对象已被其他对象引用,称为二级缓存
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap(16);
// 3. 存储单例Bean的工厂池,即存储半成品对象,对象未被引用,使用时通过工厂创建Bean,称为三级缓存
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap(16);
}
接下来,以 UserService 和 UserDao 的循环依赖为例,结合上述三级缓存描述整个过程:
-
UserService 被实例化但尚未初始化,将 UserService 存储到三级缓存。
-
UserService 属性注入需要 UserDao,但在缓存中找不到 UserDao。
-
UserDao 被实例化但尚未初始化,将 UserDao 存储到三级缓存。
-
UserDao 属性注入需要 UserService,从三级缓存中获取 UserService,并将 UserService 从三级缓存移至二级缓存。
-
UserDao 执行其他生命周期过程,并最终成为一个完整的 Bean,存储到一级缓存,并删除二、三级缓存。
-
UserService 注入 UserDao。
-
UserService 执行其他生命周期过程,并最终成为一个完整的 Bean,存储到一级缓存,并删除二、三级缓存。
通过以上步骤,UserService 和 UserDao 的循环依赖得到解决,两个 Bean 都成功完成了初始化阶段,并存储在一级缓存中。
3. 源码查看
提醒:本文发布于421天前,文中所关联的信息可能已发生改变,请知悉!
/>
Tips:清朝云网络工作室