微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring中的循环依赖

首先举个例子:A对象依赖于B对象,B对象有依赖于A对象

 class A{
     B b;
 }
 class B{
     A a;
 }

有人会问以上代码不是很正常吗?不就是相互依赖吗?

确实,不谈Spring,确实很正常

但在Spring中,由于Spring中bean对象的生命周期要遵循一定的步骤,必须是创建、注入、初始化三步,这些顺序不能乱,所以就会出现循环依赖

大家应该都知道解决spring循环依赖靠的是三级缓存

那我们就来看看这个三级缓存是如何解决spring的循环依赖的

1.首先我们先来看看一级缓存(以下代码是大致的流程,和spring源码还有点差距)

一级缓存可以解决循环依赖吗?

 一级缓存也称单例池,请看下面的图

 解释:1)首先A,B两个类中各自要注入对方的属性

            2)首先调用getBean方法获取A对象,第一次去一级缓存中查找,显然是没有的

            3)那么a是null,于是跳过if判断,初始化A对象,然后给属性b赋值

            4)开始调用getBean方法获取B对象,第一次去一级缓存中查找没有,跳过判断

            5)初始化B对象,然后给a属性赋值,发现没有,于是调用getBean方法创建A对象,这样就形成了死循环了

总结一下:ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中)

所以一级缓存不可以解决循环依赖问题

3.我们来看看二级缓存

 

 先来看个图吧:   

 解释(可以对比一级缓存)

        1)首先A,B两个类中各自要注入对方的属性

        2)首先调用getBean方法获取A对象,第一次去一级缓存中查找,显然是没有的

        3)那么a是null,于是跳过if判断,初始化A对象,不同的在这里,他往二级缓存中放了A对象(半成品对象)然后给属性b赋值

        4)开始调用getBean方法获取B对象,第一次去一级缓存中查找没有,跳过判断

        5)初始化B对象,然后给a属性赋值,不同的在这里,他会去二级缓存中查找A,于是找到了A(半成品对象),于是A就注入成功了,于是B对象就创建完成了,于是把他放到了一级缓存当去(B对象是成品对象)

        6)最后A自然也可以创建成功了,最后也放到了一级缓存当中去

总结一下:二级缓存放半成品对象,一级缓存放的是成品对象,所以二级缓存好像解决循环依赖问题

3.还是来说说二级缓存

先说结论:二级缓存不能解决循环依赖中存在代理的情况

aop是在init方法后面执行的执行时机在 postProcessAfterInitialization(bean的生命周期)

先看下面这张图:

 大家可以按照上面试着分析一下,我就不分析了,直接说结论吧

最终会发现B注的是A的原始对象,A注入B的代理对象,这样A的功能不能增强

4.终于到了三级缓存

首先我们先不谈三级缓存,看看怎么解决上述问题

很容易就可以想到,二级缓存出现的问题就在于代理创建的时机太晚了,如果在set注入之前执行就可以解决

我们来看看Spring为什么还要使用三级缓存

我说一下他的大概流程吧

他就是往三级缓存中放入了bean的工厂对象,然后判断是否存在循环依赖,如果发生了循环依赖他就提前创建代理,如果没有发生他还是在返回原始对象,需要创建代理才会创建代理

大家可以结合Spring源码和分析图,应该可以理解了

以上是set循环依赖,构造循环依赖下期再见吧,谢谢大家!!!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐