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

不足

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

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

相关推荐
hongtianzai4 分钟前
Laravel8.x核心特性全解析
java·c语言·开发语言·golang·php
AntBlack6 分钟前
Ant-Browser : 发布一个开源免费的指纹浏览器 ,欢迎体验
后端·架构·go
逸Y 仙X8 分钟前
文章十一:ElasticSearch Dynamic Template详解
java·大数据·数据库·elasticsearch·搜索引擎·全文检索
隔壁小邓10 分钟前
IDEA 中同时启动多个微服务
java·微服务·intellij-idea
:12110 分钟前
idea17创建tomcat项目(计网底层核心理解!)
java·ide·intellij-idea
楼田莉子11 分钟前
C++高性能并发内存池:三种Cache的设计及其内存申请释放
c++·后端·链表·哈希算法·visual studio
Brookty14 分钟前
网络通信核心:四元组、socket与IO机制详解
java·网络通信·网络入门
短剑重铸之日19 分钟前
《ShardingSphere解读》12 解析引擎:SQL 解析流程应该包括哪些核心阶段?(下)
数据库·后端·sql·架构·shardingsphere·分库分表
佩奇大王24 分钟前
P159 摆动序列
java·开发语言·算法
计算机学姐26 分钟前
基于SpringBoot的网吧管理系统
java·spring boot·后端·spring·tomcat·intellij-idea·mybatis