1 循环依赖方式
1.1 构造参数循环依赖
public class A{ |
<bean id="a" class="...A"> |
Spring先创建(singleton) A,A依赖B,将A放进当前创建Bean池中;然后创建B,B依赖A,将B放进当前创建Bean池中,然后发现A已经在池中。
1.2 setter方式(单例,singleton),默认方式
Spring是先将Bean对象实例化之后再设置对象属性的
1.3 setter方式(原型,prototype)
scope=“prototype”,每次请求都会创建一个实例对象
2 循环依赖(circular reference)
在 Spring 中,循环依赖是指两个或多个 Bean 之间互相依赖的情况,导致 Bean 的创建发生循环,从而无法完成依赖注入的过程。这种情况可能会导致应用程序启动失败或者出现不可预测的行为。
Spring 框架提供了一些解决循环依赖的机制:
-
提前曝光(Early Exposure): Spring 容器在创建 Bean 的过程中,会提前暴露正在创建的 Bean 实例,以解决循环依赖的问题。当一个 Bean A 依赖另一个 Bean B,而 Bean B 又依赖 Bean A 时,Spring 在创建 Bean A 的过程中,会提前暴露一个代理对象,用于处理 Bean B 对 Bean A 的依赖。这样,Bean A 可以在被完全创建之前,通过代理对象来访问 Bean B。这种方式需要使用 CGLIB 来创建代理对象。
-
构造函数注入: 使用构造函数注入来解决循环依赖问题。Spring 容器在创建 Bean 的过程中,会首先将依赖项通过构造函数传递进去,从而避免了循环依赖的问题。这种方式需要谨慎使用,因为构造函数注入会将循环依赖暴露在类的构造函数中,可能导致代码不够清晰。
-
Setter 方法注入: 使用 Setter 方法注入来解决循环依赖问题。与构造函数注入类似,通过将依赖项通过 Setter 方法注入,可以避免循环依赖的问题。与构造函数注入相比,Setter 方法注入更加灵活,可以在 Bean 创建完成后再进行依赖注入,但也需要注意循环依赖可能带来的问题。
虽然 Spring 提供了这些解决循环依赖的机制,但是在设计应用程序时,尽量避免出现循环依赖是更好的选择。循环依赖会导致代码的复杂性增加,降低程序的可维护性和可读性。
3 三级缓存解决循环依赖
-
一级缓存(singletonObjects):存放最终形态的 Bean(已经实例化、属性填充、初始化),单例池,为“Spring 的单例属性”⽽⽣。一般情况我们获取 Bean 都是从这里获取的,但是并不是所有的 Bean 都在单例池里面,例如原型 Bean 就不在里面。
-
二级缓存(earlySingletonObjects):存放过渡 Bean(半成品,尚未属性填充),也就是三级缓存中
ObjectFactory
产生的对象,与三级缓存配合使用的,可以防止 AOP 的情况下,每次调用ObjectFactory#getObject()
都是会产生新的代理对象的。 -
三级缓存(singletonFactories):存放
ObjectFactory
,ObjectFactory
的getObject()
方法(最终调用的是getEarlyBeanReference()
方法)可以生成原始 Bean 对象或者代理对象(如果 Bean 被 AOP 切面代理)。三级缓存只会对单例 Bean 生效。
3.1 Spring 创建 Bean 的流程:
-
先去 一级缓存
singletonObjects
中获取,存在就返回; -
如果不存在或者对象正在创建中,于是去 二级缓存
earlySingletonObjects
中获取; -
如果还没有获取到,就去 三级缓存
singletonFactories
中获取,通过执行ObjectFacotry
的getObject()
就可以获取该对象,获取成功之后,从三级缓存移除,并将该对象加入到二级缓存中。
[!note]
只用两级缓存够吗? 在没有 AOP 的情况下,确实可以只使用一级和三级缓存来解决循环依赖问题。但是,当涉及到 AOP 时,二级缓存就显得非常重要了,因为它确保了即使在 Bean 的创建过程中有多次对早期引用的请求,也始终只返回同一个代理对象,从而避免了同一个 Bean 有多个代理对象的问题。
4 Spring源码
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry { |
-
singletonObjects:用于存放初始化好的 bean 实例,存放完整对象。
-
earlySingletonObjects,用于存放初始化中的 bean,来解决循环依赖。存放半成品对象,属性还未赋值的对象。
-
singletonFactories:用于存放 bean 工厂,bean 工厂所生成的 bean 还没有完成初始化 bean。存放的是
ObjectFactory<?>
类型的 lambda 表达式,就是这用于处理 AOP 循环依赖的。
相互引用的bean,A依赖B,把A原始对象包装成SingletonFactory 放入三级缓存
B依赖A,B依赖的A是从singletonFactories获取bean工厂调用getObject方法生产bean放入earlySingletonObjects。