Spring三级缓存解决循环依赖问题及实现Aop

本文详细解析了Spring中如何处理A、B类的循环依赖问题,涉及构造器和setter注入,以及三级缓存(singletonObjects, earlySingletonObjects, singletonFactories)在实例化与初始化过程中的作用。重点讲述了A、B类在创建过程中的步骤和代理对象的实现原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

循环依赖

A类属性有B类,B类属性有A类,相互依赖。

依赖注入

主要有两种方式1、构造器;2、setter,其中构造器方式产生的循环依赖无解,会抛出异常。

Spring类加载主要过程

实例化->初始化,其中实例化是创建对象,初始化是填充属性。我们把实例化完成的类成为半成品,把初始化完成的类成为成品。

解决循环依赖的关键是将实例化与初始化两个过程分开。

Spring三级缓存

缓存map存储对象
一级缓存singletonObjects用来存放已经完全创建好的单例bean
二级缓存earlySingletonObjects在产生循环依赖的时候,用来存放从三级缓存中获取的半成品bean,若存在代理,其中从三级缓存中最终获取的是aop生成代理对象
三级缓存singletonFactories用来存放单例bean的ObjectFactory

A、B循环依赖加载过程

1、getSingleton("a", true) 获取a:会依次从 3个级别的缓存中找 a,此时 3个级别的缓存中都没有 a;

2、将a丢到正在创建的 beanName 列表中(singletonsCurrentlyInCreation);

3、实例化 a:A a = new A();这个时候 a 对象是早期的 a,属于半成品;

4、将早期的 a 丢到3级缓存中(singletonFactories);

5、调用 populateBean 方法,注入依赖的对象,发现 setB 需要注入 b;

6、调用getSingleton("b", true)获取 b:会依次从 3 个级别的缓存中找 a,此时 3 个级别的缓存中都没有 b;

7、将 b丢到正在创建的beanName列表中;

8、实例化 b:B b = new B();这个时候 b对象是早期的b,属于半成品;

9、将早期的 b 丢到3级缓存中(singletonFactories);

10、调用populateBean 方法,注入依赖的对象,发现 setA 需要注入 a;

11、调用 getSingleton("a", true) 获取 a:此时 a 会从第 3 级缓存中被移到第 2 级缓存,然后将其返回给 b 使用,此时 a 是个半成品(属性还未填充完毕),此时若a被代理,则会返回代理对象(aop)

12、b 通过 setA 将11中获取的 a 注入到 b中;

13、b 被创建完毕,此时b会从第3级缓存中被移除,然后被丢到1级缓存;

14、b返回给a,然后b被通过 A 类中的 setB 注入给a;

15、a 的populateBean执行完毕,即:完成属性填充,到此时a已经注入到b中了;

总结

1、一级缓存、二级缓存解决循环依赖问题;

2、三级缓存实现aop(代理对象实例化的时候,实例化对象是原始对象,若没有三级缓存,此时若根据类名直接获取对象的话,获取的是原始对象,而我们想要的肯定是通过类名直接获取代理对象,所以Spring在类加载过程中,直接将实例化的对象放入三级缓存中,从三级缓存中获取类对象的时候,判断类是否被代理,若被代理则返回代理对象)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值