Spring框架中的循环依赖和三级缓存

1.循环依赖的概述

2.三级缓存的概述

3.循环依赖的案例分析

循环依赖:

       循环依赖是指在Spring框架中创建Bean对象的过程中,多个实体类之间相互依赖,形成闭环。比如说有A,B,C三个实体类,其中A类引用了B类,B类引用了C类,而C类又引用了A类,形成了一个闭环,因此循环依赖,也被称为循环引用。

三级缓存:

   概述:

        三级缓存是Spring框架提供的三个Map集合,用于存储Bean对象在创建过程中形成的完整Bean对象和不完整的Bean对象。

fa6a63bc4477414f8c736765f6a97693.png

   一级缓存:

      一级缓存是指用于存储最终完整的Bean对象的容器,即上图中的singletonObjects集合。此容器存储的Bean对象已完成了实例化和初始化,可通过ApplicationConText接口的getBean()方法,直接获取实例化的对象。

  二级缓存:

       二级缓存是指用于存储不完整的Bean对象的容器,即上图中的earlySingletonObjects集合,此容器中存储的Bean对象完成了实例化,但还没完成初始化,因此属于“半成品”。但在循环依赖中,由于类A对象在初始化过程中需要引用另一个暂时还不存在的类B对象,导致类A对象无法完成完整的初始化过程,产生一个完整的Bean对象,但又因为类A对象被它所引用的类B所引用,此时会将暂不完整的Bean对象A暂存放于二级缓存容器中,供类B对象初始化时引用。

  三级缓存:

       三级缓存指上图中的singletonFactories集合,此集合与二级缓存的功能类似,都是用来存放暂不完整的Bean对象的容器。但与二级缓存不同的是,三级缓存中存放的Bean对象没有被其他类所引用,只是单纯存放不完整Bean对象。

案例分析:

  需求:

           假设现在有两个实体类Dao和Service,这两个类分别依赖彼此。现有个需求:分别完成这两个类对象的实例化和初始化,获取两个完整的Bean对象存放在一级缓存集合中。

   需求分析:

     如果在没有引入三级缓存的情况下,在先加载的Bean对象(Service)完成实例化后开始初始化时,由于引用了类Dao,此时会在singletonObjects(一级缓存集合)中找寻类Dao的实例化对象。由于此时类Dao的Bean对象还未被加载,因此一级缓存中并没有Dao对象。此时Service对象的创建会被暂停,转而创建Dao对象。但由于Dao也引用了Service,在Dao对象初始化过程中也会出现上面的问题,进而会创建多个不完整的Bean对象,形成一个死循环。如下图所示:

b04b7dfe05e946b891f2334f8bfa638f.png

优化方案:

        引入三级缓存概念,Bean对象在初始化过程中由于引用另一个类对象而被迫暂停时,可暂时将此不完整的Bean对象存放到三级缓存中。进而在创建引用类对象时,由于此类对象存放于三级缓存中,引用类对象在从三级缓存到一级缓存的寻找过程中,可以找寻到此类对象,因而可完成引用类对象的完整创建,打破了上面的死循环,进而完成此类对象的完整创建。

  实现步骤:

      1.Service 实例化对象,但尚未初始化,将Service存储到三级缓存;

      2.Service 属性注入,需要Dao,从缓存中获取,未获取到Dao;

      3.Dao实例化对象,但尚未初始化,将Dao存储到到三级缓存;

      4.Dao属性注入,需要Service,从三级缓存获取Service,获取到Service后将Service从三级缓存移入二级缓存;

      5.Dao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,并从三级缓存中删除此对象;

      6.Service 从一级缓存中找到Dao,完成对Dao的注入;

      7.Service执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,并从二三级缓存中删除此对象。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值