解决Spring容器自调引起的依赖冲突
lz今天在处理Spring事务的时候遇到一个有意思的坑。
大概就是我在业务层中一个Service要调用自身的其他方法,而它本身又开启了Spring声明式事务,很明显,如果直接用this执行其他要调用的方法,将会导致Spring事务失效(原因:事务本质是Aop,而Aop通过代理的方式完成,this指向会破坏代理关系从而导致事务失效)。
解决自调引起的事务失效大概有三种方法:
- 容器中注入容器本身---但是这会引起依赖循环,也就是后面要讲的。
- 采用AopContext获取当前的代理对象。
- 使用Spring的编程事务
1 | ┌─────┐ |
自然而然的想到了高版本Spring默认关闭了依赖循环,于是在配置中打开:
1 | spring: |
但是运行依旧是同样的报错,那么为什么不能解决依赖循环呢?
首先从源头开始,Spring采用三级缓存的方式来解决依赖循环:
- singletonObjects, 一级缓存
- earlySingletonObjects, 二级缓存
- singletonFactories 三级缓存
- 对象A要创建到Spring容器中,从一级缓存singletonObject获取A,不存在,开始实例化A,最终在三级缓存singletonObjectFactory添加(A,A的函数式接口创建方法),这时候A有了自己的内存地址
- 设置属性B,B也从一级缓存singletonObject获取B,不存在,开始实例化B,最终在三级缓存singletonObjectFactory添加(B,B的函数式接口创建方法),这时候B有了自己的内存地址
- B中开始给属性A赋值,此时会找到三级缓存中的A,并将A放入二级缓存中。删除三级缓存
- B初始化完成,从三级缓存singletonObjectFactory直接put到一级缓存singletonObject,并删除二级和三级缓存的自己
- A成功得到B,A完成初始化动作,从二级缓存中移入一级缓存,并删除二级和三级缓存的自己
- 最终A和B都进入一级缓存中待用户使用
了解到根本原因,那么好修改了,只要把这种构造器注入的方式改为setter注入或者@autowired
注入,便可以解决问题。
本部落格所有文章除特別聲明外,均採用 CC BY-NC-SA 4.0 許可協議。轉載請註明來自 你所不知道的物語;!
評論