spring 如何解决循环依赖问题 | 您所在的位置:网站首页 › springboot依赖报错 › spring 如何解决循环依赖问题 |
什么是循环依赖
很简单, 就是A依赖B, B依赖A. 比如 class A { private B b; } class B { private A a; }这是问题么? 当然不是, 这个完全可以在构造完对象后设置对应的属性, 像这样: A a = new A(); B b = new B(); a.setB(b); b.setA(a);那么下面这个呢. class A { private B b; public A (B b) { this.b = b; } } class B { private A a; public B (A a) { this.a = a; } }这是问题么? 当然是, 构造A对象必须使用B对象, 但是构造B对象必须使用A对象, 所以导致两个对象无法创建成功. 分析下两种情况, 第一种情况对象的构造和属性设置分开进行, 而第二种对象的构造和属性设置耦合在一起. 所以本文将第一种情况称为弱依赖, 第二种称为强依赖. 从上述代码可以知道循环依赖如果是强依赖无法解决, 弱依赖才可以处理. 那么spring可以帮助我们解决强依赖么? spring这么强大, 那当然是不行的... spring只是工具不是魔法, 它只是简化工作量而已. 所以spring只能帮我们自动解决弱依赖问题. spring 如何解决循环依赖先让大家看下spring解决循环依赖的秘籍~ A a = new A(); B b = new B(); a.setB(b); b.setA(a);...... 不管你信不信, 这就是spring处理循环依赖的思路. 先创建对象. 放到一边备用. 拿出对象并设置属性.spring会将构造完毕的对象放入一个缓存中等待用户使用, 这个缓存成为一级缓存. 一级缓存存储的都是可以直接使用的对象. 那么哪里存储没有构造完毕的对象(就叫原始对象吧)呢? 那就再加一个缓存, 称为二级缓存, 二级缓存存储原始对象, 还没有构造完毕, 不能提供给用户使用. 整理流程如下: image.png 三级缓存如果看spring源码会发现情况要比上述复杂的多, 把握整体思想: 一级缓存存储可使用的对象, 二级缓存存储未完成对象. 三级缓存用于存储对象的工厂方法, 当对象被AOP增强后, 会通过三级获取工厂方法生成增强后的代理对象, 然后将代理对象存储到二级缓存, 并删除三级缓存对应的缓存. BeanPostProcessor通过实现BeanPostProcessor可以修改创建的对象, 那对循环依赖会有影响么? 是的, 会影响. BeanPostProcessor可以在对象实例化之后更改创建的对象, 比如在BeanPostProcessor中修改B对象, 那么会在执行后将新的对象注入到A对象中, 如果至此结束则没有问题, 但是如果还要在BeanPostProcessor中修改A对象, 那spring会报错, 因为新提供的A对象不是之前注入到B对象中的对象, 如果注入成功会造成依赖的对象不一致的情况. 原型模式上面提到的各种缓存都是直接使用缓存中的对象, 如果是原型模式, 每次都需要新建对象的话怎么处理循环依赖? 答案是不能处理...spring会直接报错. 总结 spring只能处理循环依赖为弱依赖的情况. 而且需要是单例模式下. 处理思路就是将依赖双方中间设置一个缓存. 尽量不要出现循环依赖, 2.6以上版本的spring boot默认不支持循环依赖, 出现循环依赖, 就算是弱依赖也会报错, 需要设置spring.main.allow-circular-references配置为true.本文主旨是理解思想, 如有不对, 欢迎指正 ~ |
CopyRight 2018-2019 实验室设备网 版权所有 |