❒ 循环依赖场景
✔ 在创建A对象的同时需要使用的B对象,在创建B对象的同时需要使用到A对象。
✔ A → B → C → A
✔ A → A
❒ 循环依赖过程分析
→ 实例化A对象
→ 需要设置B对象属性
→ 需要要到spring容器查找B对象
→ B对象不存在
→ 实例化B对象
→ 需要设置A对象属性
→ 需要要到spring容器查找A对象
→ A对象还卡在设置B对象属性的地方,所以A对象不存在
❒ 三级缓存
singletonObjects:第一级缓存,里面放置的是已经实例化好的单例对象,是单例缓存池。
earlySingletonObjects:第二级缓存,里面存放的是提前曝光的单例对象,早期对象。简单粗暴的说就是new了对象了,但是这个对象还没填充属性。
singletonFactories:第三级缓存,里面存放的是将要被实例化的对象的对象工厂(存放 bean 工厂对象),是一个包裹对象ObjectFactory(registeredSingletons),通过getObject获取到早期对象。
❒ 为什么二级缓存不能解决代理bean循环依赖问题?
✔ 动态代理通常在Bean初始化阶段(initializeBean)通过BeanPostProcessor生成。
✔ 若仅使用二级缓存(earlySingletonObjects),代理对象无法提前暴露,导致循环依赖时注入的仍是未代理的原始对象,破坏代理逻辑的一致性。
❒ 什么情况下的bean才算是代理对象呢?
✔ 是否为代理对象,取决于是否被Spring AOP增强。如果有切面逻辑(事务、日志等),则是代理对象。
✔ 比如加了@Transactional,@Async或被自定义切面切入。
❒ 构造方法出现了循环依赖怎么解决?
✔ 原因: 由于bean的生命周期中构造函数是第一个执行的,spring框架并不能解决构造函数的的依赖注入。
✔ 解决方案: 使用@Lazy进行懒加载,什么时候需要对象再进行bean对象的创建。