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通过第二级缓存,将实例化完成,还未初始化属性值的对象,提前暴露给其它对象,解决了循环依赖的问题。

不足

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

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

相关推荐
ovensi15 小时前
Docker+NestJS+ELK:从零搭建全链路日志监控系统
后端·nestjs
武子康16 小时前
大数据-184 Elasticsearch Doc Values 机制详解:列式存储如何支撑排序/聚合/脚本
大数据·后端·elasticsearch
四月__16 小时前
http八股
后端
沐森16 小时前
rust并发
后端
喵个咪16 小时前
开箱即用的 GoWind Admin|风行,企业级前后端一体中后台框架:Casbin集成指南
后端·go
墨守城规16 小时前
FutureTask源码分析
后端
梨子同志16 小时前
Java 基础语法详解
后端
bcbnb16 小时前
详细教程:iOS应用中Swift代码混淆步骤与工具推荐
后端
气π16 小时前
【JavaWeb】——(若依 + AI)-基础学习笔记
java·spring boot·笔记·学习·java-ee·mybatis·ruoyi
expect7g16 小时前
Paimon源码解读 -- Compaction-8.专用压缩任务
大数据·后端·flink