spring循环依赖问题

循环依赖问题

循环依赖的两种形式:构造器的方式注入、setter 的方式注入。其中构造依赖会报错

spring解决循环依赖使用的是三级缓存机制,我们知道创建一个bean可以分为实例化和初始化两个过程,解决循环依赖的核心就是把实例化和初始化两个操作分开,也就是说允许提前暴露出一个半成品对象。

一级缓存存放的是一个完整的bean实例对象,也就是实例化和初始化都完成了。

二级缓存存放的是一个半成品的实例化对象,也就是只完成了实例化,但是并没有完成初始化操作。

三级缓存可以理解为存储了一个单例的工厂,里面是一个匿名内部类,二级缓存的对象就是从这个工厂中获取的。三级缓存提供了一个提前生成代理的方法,而不是直接生成代理。

  1. 假设A、B循环引用,我们要创建一个A对象,首先从一级缓存中获取A对象,发现不存在,然后我们实例化A,同时将其添加到三级缓存中。这时候A有了自己的内存地址。
  2. 然后我们要设置A对象的属性B,也是先从一级缓存中获取B对象,不存在,然后开始实例化B,并将B对象添加到三级缓存中。此时B也有了自己的内存地址。
  3. 再然后B开始给属性A赋值,此时去三级缓存中找到实例A对象,同时将A放入二级缓存,删除三级缓存中的A。
  4. 现在B初始化完成了,对象B可以直接从三级缓存跳到1级缓存了,二级缓存和三级缓存都不存在B了。
  5. B初始化完成之后,A就可以得到B完成初始化的工作了,那么A就可以从二级缓存移入到一级缓存了。
  6. 最后AB都是完整的对象了,并且都在1级缓存了。

为什么需要三级缓存

首先,三级缓存的value类型是ObjectFactory,是一个函数式接口,它存在的意义是保证在整个容器的运行过程中同名的bean对象只能有一个。即使一个对象需要被代理,那么它依然会优先生成一个普通的对象。但是普通对象和代理对象是不能同时出现在容器中的,因此当一个对象需要被代理的时候,就要使用代理对象覆盖掉之前的普通对象,在实际的调用过程中,是没有办法确定什么时候对象被使用,所以就要求某个对象被调用的时候,优先判断此对象是否需要被代理,如果需要,我们就可以向三级缓存传入一个lambda表达式,通过lambda表达式来执行对象的覆盖过程,也就是getEarlyBeanReference()方法。

因此,所有的bean对象在创建的时候要优先放到三级缓存中,在后续的使用过程中,如果需要被代理则返回代理对象,如果不需要被代理,则直接返回普通对象。

你可能感兴趣的:(Spring,java,动态代理,spring,缓存,java)