SpringBoot 启动报循环依赖问题
问题现象
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'a': Bean with name 'a' has been injected into other beans [b] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:622)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:515)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:277)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1251)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1171)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:593)
... 61 common frames omitted
问题原因分析
原因:
我们知道,spring三级缓存一定程度上解决了循环依赖问题。A对象在实例化之后,属性赋值 【opulateBean(beanName,mbd,instanceWrapper)】执行之前,将ObjectFactory添加至三级缓存中,从而使得在B对象实例化后的属性赋值过程中,能从三级缓存拿到ObjectFactory,调用getobject0方法拿到A的引用,B由此能顺利完成初始化并加入到OC容器。此时A对象完成属性赋值之后,将会执行初始化 【initializeBean(beanName, exposedObject, mbd方法】,重点是@Async注解的处理正是在这地方完成的,其对应的后置处理器AsyncAnnotationBeanPostProcessor,在postProcessAfterlnitialization方法中将返回代理对象,此代理对象与B中持有的A对象引用不同,导致了以上报错。补充:
- context.getBean(A)开始创建A,A实例化完成后给A的依赖属性b开始赋值~
- context.getBean(B)开始创建B,B实例化完成后给B的依赖属性a开始赋值~
- 重点:此时因为A支持循环依赖,所以会执行A的getEarlyBeanReference方法得到它的早期引用。而执行getEarlyBeanReference()的时候因为@Async根本还没执行,所以最终返回的仍旧是原始对象的地址
- B完成初始化、完成属性的赋值,此时属性field持有的是Bean A原始类型的引用~
- 完成了A的属性的赋值(此时已持有B的实例的引用),继续执行初始化方法initializeBean(...),在此处会解析@Aysnc注解,从而生成一个代理对象,所以最终exposedObject是一个代理对象(而非原始对象)最终加入到容器里~
- 尴尬场面出现了:B引用的属性A是个原始对象,而此处准备return的实例A竟然是个代理对象,也就是说B引用的并非是最终对象(不是最终放进容器里的对象)
- 执行自检程序:由于allowRawInjectionDespiteWrapping默认值是false,表示不允许上面不一致的情况发生,so最终就抛错了~
- 代理的创建时机
- 初始化之后 (无循环依赖时)
- 实例创建后, 依赖注入前 (有循环依赖时), 并暂存于二级缓存
- 代理的创建时机
解决方案
1)在A类上加@Lazy,保证A对象实例化晚于B对象;
2)在A类上使用@DependsOn({"b"})注解,保证A对象实例化晚于B对象(注意如果AB两个类相互DependsOn,也会形成循环依赖)
3)设置 AbstractAutowireCapableBeanFactory.setAllowRawInjectionDespiteWrappin(true),不会报错但会导致B持有的A引用不是最终的代理对象:
4)不使用@Async注解,通过自定义异步工具类发起异步线程;
参考
链接1:https://wenku.baidu.com/view/0bbb583b5aeef8c75fbfc77da26925c52dc59151.html
连接2:https://blog.csdn.net/yxh13521338301/article/details/117450763
SpringBoot 启动报循环依赖问题的更多相关文章
- SpringBoot启动报错Failed to determine a suitable driver class
SpringBoot启动报错如下 Error starting ApplicationContext. To display the conditions report re-run your app ...
- springboot 启动报错"No bean named 'org.springframework.context.annotation.ConfigurationClassPostProcessor.importRegistry' available"
1.问题 springboot启动报错 "D:\Program Files\Java\jdk-11\bin\java.exe" -XX:TieredStopAtLevel=1 -n ...
- springboot bean的循环依赖实现 源码分析
springboot bean的循环依赖实现 源码分析 本文基于springboot版本2.5.1 <parent> <groupId>org.springframework. ...
- SpringBoot启动报错:ould not be registered. A bean with that name has already been defined in file and overriding is disabled.
SpringBoot启动报错 ***************************APPLICATION FAILED TO START*************************** Des ...
- springboot启动报错 Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.
新建了一个springboot项目报一下错误: Failed to configure a DataSource: 'url' attribute is not specified and no em ...
- SpringBoot启动报:Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
使用spring boot对项目改造,启动报错: Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel m ...
- 折腾了我两天的springboot数据源datasource循环依赖问题,都被搞疯掉了
在做项目重构的时候增加了两个功能 1.多数据源. 2.token的验证从以前的数据库验证,移到了redis端. 1.多数据源使用 druid-spring-boot-starter 套件 其核心代码如 ...
- 《Springboot极简教程》问题解决:Springboot启动报错 Whitelabel Error Page: This application has no explicit mapping for(转)
13.2 Spring Boot启动报错:Whitelabel Error Page 13.2 Spring Boot启动报错:Whitelabel Error Page 问题描述 Whitelabe ...
- springboot启动报错:Failed to configure a DataSource
一.背景 springboot的出现,让项目搭建变得更方便快捷,同时简化掉很多的样板化配置代码,提高开发效率. 通过idea生成springboot项目,启动报错:Failed to configur ...
- springboot启动报错start bean 'eurekaAutoServiceRegistration' NullPointerException
解决方案参考:https://blog.csdn.net/hhj13978064496/article/details/82825365 我将eureka的依赖包放到了依赖包的最下面,启动报错, 如下 ...
随机推荐
- 记OPNsense防火墙的安装过程 - 安全
前些天在网上看到防火墙软件OPNsense,对其有了兴趣,以前写过一个其前面的一个软件M0n0wall( 关于m0n0wall的安装及配置 ),当时也是非常有名的防火墙,现在有了OPNsense,这个 ...
- win32com操作word API精讲 第十集 Paragraphs & Paragraph接口 (一)
本课程<win32com操作word API精讲&项目实战>以视频为主,文字为辅,公众号ID:一灯编程 在word编程中,Range和Paragraph(s)接口无愧于劳模接口的称 ...
- Sublime下运行javascript,并带彩色提示
最近和各种同事磨合技术,自闭中~ 首先让JS在Sublime上运行 去下载Node.js并且安装 安装完成后 cmd 输入 node -v 查看安装是否成功. 接着打开Sublime - 工具 > ...
- 【分析笔记】NXP PCF85263 设备驱动分析笔记
驱动移植 供应商无法提供相应的驱动程序,不过在 linux 最新的内核倒是有一份 pcf85363 的驱动,看代码并核对寄存器功能,是可以兼容 pcf85263 芯片.只是我们用的内核比较老 linu ...
- day03-模型数据
模型数据 1.数据放入request 说明:开发中,控制器/处理器中获取的数据如何放入request域,然后在前端(vue/jsp/...)取出显示? 先来看一个例子 应用实例需求:表单提交信息,后端 ...
- 移动 WEB 布局方式之 rem 适配布局 ---- 苏宁首页案例制作
一.技术选型 二.搭建相关文件夹结构 三.设置视口标签以及引入初始化样式 四.设置公共common.less 文件 common.less //设置常见的屏幕尺寸大小,修改里面的html 文字大小 / ...
- FAQ os.system调用失效问题
os.system调用失效问题 背景 有个学员反馈allure无法生成报告 # 示例代码 import pytest,os def test_os(): pass if __name__ == '__ ...
- python学习day04
1.基本数据类型之布尔值bool 1.用来判断事物的对错,是否可行,用于流程控制中 2.只有两种状态: True:对的.真的.可行的 False:错的.假的.不可行的 3.python中所有的数据都自 ...
- 通过URL地址将图片保存到本地
今天一朋友问我如何通过URL地址将图片保存下来. 特地找了些资源,实现了一下代码: using System; using System.Drawing; using System.Drawing.I ...
- 树莓派4B安装OPENCV4.0
参考 : https://www.pyimagesearch.com/2018/09/26/install-opencv-4-on-your-raspberry-pi/ Step #1: Expand ...