文章目录
Spring 三级缓存
Spring 中循环依赖的现象
1、构造器循环依赖
- 构造器循环依赖指的是在 Bean 的构造函数中存在相互依赖的情况。当 Spring 容器在创建 Bean 时,会先调用构造函数来实例化对象。如果存在构造器循环依赖,就会陷入一个死循环,因为创建一个 Bean 需要先创建另一个 Bean,而创建另一个 Bean 又需要先创建第一个 Bean。Spring 无法解决这种循环依赖,会直接抛出
BeanCurrentlyInCreationException异常。
2、field 属性注入循环依赖
- 单例(singleton)scope 下 setter 方法的循环依赖:单例 Bean 在 Spring 容器中只会创建一个实例。对于使用 setter 方法进行属性注入的单例 Bean,Spring 可以利用三级缓存机制来解决循环依赖问题。其核心原理是将 Bean 的实例化和初始化过程分离,在实例化后将 Bean 提前曝光到缓存中,当其他 Bean 依赖该 Bean 时,可以从缓存中获取到未完全初始化的 Bean 实例进行注入。
- 原型(prototype)scope 的循环依赖:原型 Bean 每次请求都会创建一个新的实例。由于每次创建都是新的对象,Spring 无法像处理单例 Bean 那样利用缓存来解决循环依赖问题。因此,对于原型 Bean 的循环依赖,Spring 不会进行处理,需要开发者自己解决。
Spring 真正创建 Bean 对象的核心类及过程
Spring 创建 Bean 对象的最核心方法为 AbstractAutowireCapableBeanFactory#doCreateBean,在这个方法中,会依次完成 Bean 对象实例化、属性注入、调用初始化方法进行一些初始化操作。
-
createBeanInstance方法此方法的核心任务是实例化 Bean 对象,其本质是调用对象的构造方法来创建对象实例。在 Spring 框架里,它会依据 Bean 的定义信息,选择合适的构造函数来创建对象。这可能涉及到无参构造函数、有参构造函数的选择,甚至可能使用工厂方法来创建对象。
-
populateBean方法该方法的主要作用是对 Bean 的依赖属性进行注入,常见的如使用
@Autowired注解进行自动注入。在这个阶段,Spring 会查找 Bean 所依赖的其他 Bean,并将这些依赖的 Bean 注入到当前 Bean 中。 -
initializeBean方法此方法主要用于调用 Bean 的初始化方法,例如实现了
InitializingBean接口的afterPropertiesSet方法,或者在 Bean 定义中指定的initMethod方法。这些方法通常用于在 Bean 的属性注入完成后,进行一些初始化操作。
Spring 解决循环依赖的前提条件
- 不全是构造器方式的循环依赖:如果所有的循环依赖都是通过构造器注入实现的,Spring 无法打破循环依赖的死循环,因此必须至少有一部分依赖是通过 setter 方法或其他非构造器方式注入的。
- 必须是单例:Spring 的三级缓存机制是基于单例 Bean 的特性实现的,只有单例 Bean 才能保证在整个应用程序的生命周期中只有一个实例,并且可以被缓存和复用。对于原型 Bean,每次请求都会创建新的实例,无法使用缓存来解决循环依赖问题。
三级缓存的作用
在 Spring 中,三级缓存主要用于解决单例 Bean 的循环依赖问题。循环依赖指的是两个或多个 Bean 之间相互依赖,形成一个闭环。例如,Bean A 依赖 Bean B,而 Bean B 又依赖 Bean A。Spring 使用三级缓存来巧妙地处理这种情况,确保单例 Bean 能够正确创建。
注意:
- 三级缓存只能解决 setter 注入的循环依赖,无法解决构造器注入的循环依赖;
- 原型(prototype)作用域的 bean 无法解决循环依赖;
- 如果 Bean 有 AOP 代理,三级缓存中的 ObjectFactory 会返回代理对象;
从 getBean(AbstractBeanFactory#getBean(java.lang.String))源码看调用时序图:
1. getBean(A) // AbstractBeanFactory
-> doGetBean(A)
-> getSingleton(A) [一级缓存没有] // DefaultSingletonBeanRegistry
-> createBean(A) // AbstractAutowireCapableBeanFactory
-> doCreateBean(A)
-> 实例化A
-> addSingletonFactory(A) [A加入三级缓存]
-> populateBean(A) [填充属性]
-> getBean(B) [发现依赖B]
-> doGetBean(B)
-> getSingleton(B) [一级缓存没有]
-> createBean(B)
-> doCreateBean(B)
-> 实例化B
-> addSingletonFactory(B) [B加入三级缓存]
-> populateBean(B) [填充属性]
-> getBean(A) [发现依赖A]
Spring三级缓存解析

最低0.47元/天 解锁文章
1036

被折叠的 条评论
为什么被折叠?



