Spring源码-08循环依赖
2021-11-20 17:46:33 10 举报
Spring循环依赖
作者其他创作
大纲/内容
解决方法:在AServices的构造方法上加@Lazy注解,这样BService的构造方法就可以用
比如AService和BService都是原型的,AService getBean的时候去创建,在注入BService的时候,因为AService是原型,是拿不到刚才创建的AService的
单例池,缓存经过了完整生命周期的bean
@Transaction,依赖注入
最终的BService的逻辑
是在循环依赖是,且存在AOP执行的
如果有代理对象呢?
span style=\"font-size: inherit;\
怎么解决呢?
singletonObjects
执行2步骤
AService{@AutowiredBService bservice@Tranctionpublic void test(){sout(bservice);}}BService{@AutowiredAService aservice;public void test(){sout(aservice);}}
Spring是怎么做的呢?
加入二级缓存zhouyuMap
代码原理
构造方法中,依赖注入
循环依赖:先创建AService,执行AService的声明周期1.先实例化一个AService-->得到一个对象2.填充BService-->去单例池找BService-->没有就创建3.填充其他属性4.初始化前,初始化5.初始化后6.放入单例池
问题:有AOP返回的应该是代理对象!!!
原因是类似的,因为AService在注入BService时,BService的AService属性没问题,BService会走完流程,自然得到的就是异步代理对象
三级缓存singletonObjects
singletonFactories
earlySingletonObjects
在创建AService:第一步是不好判断的,但是我们在创建BService:第二步好判断
但是在BService注入的是AService的原始对象,此时就有问题!!!
二级缓存earlySingletonObjects
AbstractAutoProxyCreator.java
存在的问题
问题:如果提前进行AOP,那执行到初始化后要进行判断的
两个原型Bean依赖注入不能解决,只要里面有一个是单例的,都可以解决
自己注入自己,和上面是一样的!
类似于我们二级缓存图中的zhouyuMap
此时这种情况就会形成循环依赖
此时2步骤执行完,执行下面的步骤
缓存未经过完整生命周期的bean,如果某个bean出现了循环依赖, 就会提前把这个暂时未经过完整生命周期的bean放入earlySingletonObjects中,这个bean如果 要经过AOP,那么就会把代理对象放入earlySingletonObjects中,否则就是把原始对象放入 earlySingletonObjects,但是不管怎么样,就是是代理对象,代理对象所代理的原始对象也是 没有经过完整生命周期的,所以放入earlySingletonObjects我们就可以统一认为是未经过完整 生命周期的bean
问题:怎么判断AService出现了循环依赖呢
创建BService,执行BService的声明周期1.先实例化一个BService-->得到一个对象2.填充AService-->去单例池找AService-->没有就创建3.填充其他属性4.初始化前,初始化5.初始化后6.放入单例池
@Tranction并不会报错,为什么?难道和@Async不一样嘛?
初始化后调用AOP
虽然我们的BService中注入的时候是AService的原始对象,但是注入的和我操作的是一个AService对象,所以后面我对AService赋值其他的操作就是对BService注入的AService的操作所以循环依赖就解决了!!!
我们去调整AOP的执行顺序也就是如果AService出现了循环依赖,提前进行AOP
现象1存在的另外一种情况就是异步,在初始化时,返回的时异步的代理对象,但是呢注入的却是循环依赖,提前AOP的对象,这样肯定会报错,怎么办呢?
现象2:如果把@Asyn注入带BService的test方法上就没问题,和顺序有关,因为在service包下AService在BService的上面
那怎么才能拿到代理对象呢?从二级缓存中拿
三级缓存的作用
缓存的是一个ObjectFactory,也就是一个Lambda表达式。在每个Bean 的生成过程中,经过实例化得到一个原始对象后,都会提前基于原始对象暴露一个Lambda表达 式,并保存到三级缓存中,这个Lambda表达式可能用到,也可能用不到,如果当前Bean没有出 现循环依赖,那么这个Lambda表达式没用,当前bean按照自己的生命周期正常执行,执行完后 直接把当前bean放入singletonObjects中,如果当前bean在依赖注入时发现出现了循环依赖 (当前正在创建的bean被其他bean依赖了),则从三级缓存中拿到Lambda表达式,并执行 Lambda表达式得到一个对象,并把得到的对象放入二级缓存((如果当前Bean需要AOP,那么 执行lambda表达式,得到就是对应的代理对象,如果无需AOP,则直接得到一个原始对象)
比如
真正打破循环依赖的Map,因为它和zhouyuMap是相等的作用,有它的存在,在BService注入AService的时候,才有值去填充
解决方案:在BService的字段AService上加上@Lazy注解,在创建BService的时候,AService是因为@Lazy的原因注入的一个代理对象,但是在真正用的时候,失去单例池拿对象,也就是我们的异步产生的代理对象
0 条评论
下一页