循环依赖

80 阅读2分钟

循环依赖问题是指两个或多个 Bean 之间存在依赖关系,形成一个循环引用的情况。Spring 提供了一级缓存、二级缓存和三级缓存来解决不同情况下的循环依赖问题。

单例对象中的set方法的循环依赖

  1. 一级缓存: 一级缓存是 Spring 容器中默认的缓存机制,用于存放完全初始化好的 Bean。但是,一级缓存无法解决循环依赖的问题,因为在循环依赖时,无法提前拿到完全初始化好的 Bean。

  2. 二级缓存: 二级缓存是用于解决循环依赖的关键。在调用 a.getBean() 时,会先将 a 的半成品放入 singletonFactories(二级缓存)中,然后调用 a.setB() 时,会先去二级缓存查找 b 的半成品,如果没有,再去调用 b.getBean()。这样可以防止陷入死循环。

  3. 三级缓存和工厂: 为了解决使用代理对象进行功能增强时的问题,引入了三级缓存 earlySingletonObjects 和一个工厂。工厂的作用是创建代理对象或者原始对象。工厂创建对象的时机分为两种情况:

    • 有循环依赖,提前创建代理返回。
    • 没有循环依赖,返回原始对象。

构造循环依赖问题

  1. 构造方法解决循环依赖: 在创建 a 对象时,提供 b 的代理对象,并在 b 构造方法中注入 a。这样 a 可以顺利初始化。调用 b 构造方法时,可以从一级缓存中取到 a 对象,顺利创建。
  2. ObjectFactory 解决构造循环依赖: 与第一种方法类似,唯一的不同之处在于,需要在 b 的构造方法中注入一个 ObjectFactory 来起到推迟 b 的创建的作用。