spring ioc的循环依赖问题
创始人
2024-03-17 22:29:49
0

spring ioc的循环依赖问题

  • 什么是循环依赖
  • spring中循环依赖的场景
    • 通过构造函数注入时的循环依赖
    • 通过setter或@Autowired注入时的循环依赖
  • 循环依赖的处理机制
    • 原型bean循环依赖
    • 单例bean通过构造函数注入循环依赖
    • 单例bean通过setter或者@Autowired注入的循环依赖
      • 三级缓存
      • 对象的创建分为两步
      • 循环依赖的处理机制
  • 回顾bean的创建流程如何处理循环依赖
    • AbstractBeanFactory#doGetBean
    • AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])
    • AbstractAutowireCapableBeanFactory#doCreateBean
      • DefaultSingletonBeanRegistry#addSingletonFactory
      • AbstractAutowireCapableBeanFactory#populateBean
    • AbstractAutowireCapableBeanFactory#applyPropertyValues
    • BeanDefinitionValueResolver#resolveValueIfNecessary
    • BeanDefinitionValueResolver#resolveReference
    • AbstractBeanFactory#getBean(java.lang.String)
    • AbstractBeanFactory#doGetBean
    • DefaultSingletonBeanRegistry#getSingleton(java.lang.String)
    • DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

什么是循环依赖

spring ioc的循环依赖通常是指bean与bean之间的相互依赖,
例如A持有对B的引用、B持有对A的引用,形成一个闭环,

在这里插入图片描述

相对于这种我们一眼可以看出来的相互引用,
实际引用中可能比这复杂、也隐蔽的多,
要隐蔽、复杂的多,
形成一个环形依赖。

spring中循环依赖的场景

通过构造函数注入时的循环依赖

通过setter或@Autowired注入时的循环依赖

其中,构造函数注入的循环依赖无法解决,只能抛出BeanCurrentlyCreationException异常,
在解决循环依赖时,spring采用的是提前暴露对象的方法。

spring的循环依赖基于Java的引用传递,
当获得对象的引用时,对象属性可以延后设置,
而通过构造器注入时,对象属性则必须在引用之前设置。

setter或@Autowired相当于是获得对象的引用。

循环依赖的处理机制

我们先来回顾一下bean的作用范围,
singleton:单例,spring默认的scope,容器中只存在一个对象;
prototype:原型,每次getBean都会返回一个新的对象;

单例模式bean的生命周期与容器相同,
原型模式bean,spring框架只负责创建,并不负责销毁。

原型bean循环依赖

无法解决,
对于原型模式的bean初始化过程中,
无论是通过构造器还是属性注入产生的循环依赖,spring都直接会抛出异常。

单例bean通过构造函数注入循环依赖

无法解决。

单例bean通过setter或者@Autowired注入的循环依赖

可以解决,

spring是通过三级缓存来解决循环依赖问题的。

三级缓存

一级缓存:单例池;
二级缓存:earlySingletonObjects;
三级缓存:singletonFactories。

对象的创建分为两步

1、实例化bean;
2、设置属性值。

循环依赖的处理机制

A和B互相依赖,

假如先去创建A,
A实例化后先把自己放入三级缓存,目的是为了提前暴露,
然后发现依赖B,
接着创建B,B依赖A,
B会去三级缓存中找A,使用并将A放入二级缓存,
B创建完后会把自己放入一级缓存,
A使用一级缓存中的B。

回顾bean的创建流程如何处理循环依赖

AbstractBeanFactory#doGetBean

在这里插入图片描述

这里,

	sharedInstance = getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It might have been put there// eagerly by the creation process, to allow for circular reference resolution.// Also remove any beans that received a temporary reference to the bean.destroySingleton(beanName);throw ex;}});

的lambda表达式就相当于传入了一个方法,

另外getSingleton会将最后创建好的对象放入单例池。

AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[])

在这里插入图片描述

AbstractAutowireCapableBeanFactory#doCreateBean

在这里插入图片描述

DefaultSingletonBeanRegistry#addSingletonFactory

放入三级缓存

在这里插入图片描述

AbstractAutowireCapableBeanFactory#populateBean

填充属性

在这里插入图片描述

AbstractAutowireCapableBeanFactory#applyPropertyValues

在这里插入图片描述

BeanDefinitionValueResolver#resolveValueIfNecessary

在这里插入图片描述

BeanDefinitionValueResolver#resolveReference

接下来这是获取依赖

在这里插入图片描述

AbstractBeanFactory#getBean(java.lang.String)

在这里插入图片描述

AbstractBeanFactory#doGetBean

在这里插入图片描述

DefaultSingletonBeanRegistry#getSingleton(java.lang.String)

在这里插入图片描述

DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)

在这里插入图片描述

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...