乐趣区

关于java:你真的懂Spring解决循环依赖吗

前言

咱们常常会被问到一个问题:Spring 是如何解决循环依赖的问题的。这个问题算是对于 Spring 的一个高频面试题,因为如果不刻意研读,置信即便读过源码,面试者也不肯定可能一下子思考出个中神秘。

本文次要针对这个问题,从源码的角度对其实现原理进行解说。

一、什么是循环依赖

多个 bean 之间相互依赖,造成了一个闭环。比方:A 依赖于 B、B 依赖于 c、c 依赖于 A

通常来说,如果问 spring 容器外部如何解决循环依赖,肯定是指默认的单例 Bean 中,属性相互援用的场景。也就是说,Spring 的循环依赖,是 Spring 容器注入时候呈现的问题。

二、Spring 如何解决循环依赖

1、Spring 中单例 Bean 的三级缓存

第一级缓存〈也叫单例池)singletonObjects: 寄存曾经经验了残缺生命周期的 Bean 对象

第二级缓存: earlySingletonObjects,寄存晚期裸露进去的 Bean 对象,Bean 的生命周期未完结(属性还未填充残缺)

第三级缓存: Map<String, ObiectFactory<?>> singletonFactories,寄存能够生成 Bean 的工厂

2、Spring 中 Bean 的生命周期

3、Bean 初始化次要办法

getSingleton:心愿从容器外面取得单例的 bean,没有的话

doCreateBean: 没有就创立 bean

populateBean: 创立完了当前,要填充属性

addSingleton: 填充完了当前,再增加到容器进行应用

4、具体阐明

A 创立过程中须要 B,于是 A 将本人放到三级缓存外面,去实例化 B

B 实例化的时候发现须要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了 A 而后把三级缓存外面的这个 A 放到二级缓存外面,并删除三级缓存外面的 A

B 顺利初始化结束,将本人放到一级缓存外面(此时 B 外面的 A 仍然是创立中状态)而后回来接着创立 A,此时 B 曾经创立完结,间接从一级缓存外面拿到 B,而后实现创立,并将 A 放到一级缓存中。

5、图解

三、为什么应用三级缓存

1、应用一级缓存

实例化 A -> 将半成品的 A 放入 singletonObjects 中 -> 填充 A 的属性时发现取不到 B -> 实例化 B -> 从 singletonObjects 中取出 A 填充 B 的属性 -> 将成品 B 放入 singletonObjects-> 将 B 填充到 A 的属性中 -> 将成品 A 放入 singletonObjects。

问题:这种根本流程是通的,然而如果在整个流程进行中,有另一个线程要来取 A,那么有可能拿到的只是一个属性都为 null 的半成品 A,这样就会有问题。

2、应用二级缓存

a)应用 singletonObjects 和 earlySingletonObjects

成品放在 singletonObjects 中,半成品放在 earlySingletonObjects 中

流程能够这样走:实例化 A -> 将半成品的 A 放入 earlySingletonObjects 中 -> 填充 A 的属性时发现取不到 B -> 实例化 B -> 将半成品的 A 放入 earlySingletonObjects 中 -> 从 earlySingletonObjects 中取出 A 填充 B 的属性 -> 将成品 B 放入 singletonObjects, 并从 earlySingletonObjects 中删除 B -> 将 B 填充到 A 的属性中 -> 将成品 A 放入 singletonObjects 并删除 earlySingletonObjects。

问题:这样的流程是线程平安的,不过如果 A 上加个切面(AOP),这种做法就没法满足需要了,因为 earlySingletonObjects 中寄存的都是原始对象,而咱们须要注入的其实是 A 的代理对象。

b)应用 singletonObjects 和 singletonFactories

成品放在 singletonObjects 中,半成品通过 singletonFactories 来获取

流程是这样的:实例化 A -> 创立 A 的对象工厂并放入 singletonFactories 中 -> 填充 A 的属性时发现取不到 B -> 实例化 B -> 创立 B 的对象工厂并放入 singletonFactories 中 -> 从 singletonFactories 中获取 A 的对象工厂并获取 A 填充到 B 中 -> 将成品 B 放入 singletonObjects, 并从 singletonFactories 中删除 B 的对象工厂 -> 将 B 填充到 A 的属性中 -> 将成品 A 放入 singletonObjects 并删除 A 的对象工厂。

问题:这样的流程也实用于一般的 IOC,但如果 A 上加个切面(AOP)的话,这种状况也无奈满足需要,因为每次通过 singletonFactories.getObject() 获取的代理对象都不同。

参考:《2020 最新 Java 根底精讲视频教程和学习路线!》
链接:https://juejin.cn/post/693974…

退出移动版