Spring IOC如何解决循环依赖的问题?

Spring IOC如何解决循环依赖的问题?

引言

Spring根据IOC控制反转的思想,将Bean(对象)的生命周期交由Spring IOC容器来管理,当你需要使用一个对象的时候,Spring IOC容器会自动帮你创建该对象的实例并初始化,大大降低的代码的耦合性。

我们知道,如果对象A引用了对象B,对象B又引用了对象A,那么在创建对象A的时候,就会去创建对象B,创建对象B的时候又会去创建对象A,...如此便产生了对象的循环依赖的问题。Spring IOC是如何解决的呢?

三级缓存

Spring IOC是通过三级缓存机制来解决循环依赖问题的,每级缓存都是一个Map:

  • 一级缓存:singletonObjects,key为BeanName,value为Bean,是放置完全体Bean的地方,所有的Bean最终都要放在一级缓存里,获取Bean也先从一级缓存开始获取
  • 二级缓存:earlySingletonObjects,key为BeanName,value为Bean,是放置已经实例化完成,但还没有填充属性值的Bean的地方
  • 三级缓存:singletonFactories,key为BeanName,value为对象工厂(ObjectFactory),Spring IOC在实例化一个Bean时,为这个Bean创建一个对象工厂,并将对象工厂放置在第三缓存中

解决循环依赖

  1. 当我们在程序中使用到了对象A,Spring IOC容器就会先创建对象A:
    • 在对对象A实例化的过程中,还会为对象A创建一个对象工厂,并将对象工厂放置在第三缓存中:
      • 对象工厂用于在进行代理等操作的时候,可以通过第三级缓存获取对象的包装对象。
    • 在实例化对象A的过程中,会发现引用了对象B:
      • Spring IOC容器并未在缓存中找到对象B,就会走对象B的创建流程:
        • Spring IOC容器在实例化对象B的时候,又发现了对象B引用了对象A,此时,Spring IOC在第二级缓存中找到了已经实例化但没有初始化的对象A,
        • 将第二级缓存中的对象A赋值给对象B,便可以继续完成对象B的实例化,并将实例化完的对象B放到第二级缓存中
    • 此时,Spring IOC容器就可以在第二级缓存中找到对象B,将其赋值给对象A,完成对象A的实例化
  2. 实例化完成的对象A,会被放到第二级缓存中,此时,对象A还没有初始化属性赋值
  3. Spring IOC容器将对象A的属性值初始化完成后,便会将对象A放到第一级缓存中,提供给程序使用。

可以看到,Spring IOC通过第二级缓存,将实例化完成,还未初始化属性值的对象,提前暴露给其它对象,解决了循环依赖的问题。

不足

由于放在缓存中的额对象都是同一个对象,每次获取的都是同一个对象,也就是单例模式,在这种单例模式下,才可以通过缓存来解决循环依赖的问题。

对于多例模式,每次获取的都是不同的对象,也就无法通过缓存的方式来解决循环依赖问题。

相关推荐
咸鱼2.015 分钟前
【java入门到放弃】需要背诵
java·开发语言
椰猫子26 分钟前
Java:异常(exception)
java·开发语言
GreenTea1 小时前
一文搞懂Harness Engineering与Meta-Harness
前端·人工智能·后端
win x1 小时前
Redis 使用~如何在Java中连接使用redis
java·数据库·redis
星晨雪海2 小时前
基于 @Resource 的支付 Service 多实现类完整示例
java·开发语言
阿维的博客日记2 小时前
什么是逃逸分析
java·juc
Ricky_Theseus2 小时前
C++右值引用
java·开发语言·c++
Rick19932 小时前
Java内存参数解析
java·开发语言·jvm
我是大猴子3 小时前
Spring代理类为何依赖注入失效?
java·后端·spring
勿忘,瞬间3 小时前
多线程之进阶修炼
java·开发语言