广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Springboot详细讲解循环依赖
  • 295
分享到

Springboot详细讲解循环依赖

2024-04-02 19:04:59 295人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录一、循环依赖二、循环依赖形成条件(使用构造器注入)三、循环依赖形成条件(@Aysnc注解的bean生成了对象的代理)四、针对以上问题对spring如何解决循环依赖进行详细阐述一、

一、循环依赖

顾名思义多个类中的依赖形成了环路,形成了类似于死的情况,导致SpringBoot在启动时无法为我们创建Bean。通俗来说 就是beanA中依赖了beanB,beanB中也依赖了beanA。

spring是支持循环依赖的,但是默认只支持单例的循环依赖,如果bean中依赖了原型bean,则需要加上lookup方法。Spring会为我们解决循环依赖。

@Autowired是通过三级缓存来解决循环依赖的。

@Autowired进行属性注入可以解决循环依赖。原理是: Spring控制了bean的生命周期,先实例化bean,后注入bean的属性。 Spring中记录了正在创建中的bean(已经实例化但还没初始化完毕的bean),所以可以再注入属性是,从记录的ben中去依赖的对象。

相对而言,单纯使用构造器注入就无法解决循环依赖。因为在构造时就需要传入依赖的对象,导致无法实例化。但是 构造器注入可以使用@Lazy解决循环依赖,在实例化时,传入代理对象,真正使用时才会生成真正的对象。

二、循环依赖形成条件(使用构造器注入)

1、使用构造方法的方式来注入依赖,并且类A中依赖类B,类B也同时依赖类A,这样两个类都无法正常进行Bean的创建,就会抛出异常:BeanCurrentlyInCreationException

@Component
public class A {
    private B b;
    @Autowired
    public A(B b) {
        this.b = b;
    }
}
@Component
public class B {
    private A a;
    @Autowired
    public B(A a) {
        this.a = a;
    }
}

解决方法之一:可以使用lazy注解,延迟加载依赖

@Component
public class A {
    private B b;
    @Autowired
    @Lazy
    public A(B b) {
        this.b = b;
    }
}
@Component
public class B {
    private A a;
    @Autowired
    @Lazy
    public B(A a) {
        this.a = a;
    }
}

三、循环依赖形成条件(@Aysnc注解的bean生成了对象的代理)

日志中可以看到是 tPartnerOrgService 这个bean出现了循环依赖

我在tPartnerOrgService 中使用了@Aysnc注解 进行异步处理,而@Aysnc注解的bean生成了对象的代理,导致Spring bean最终加载的不是一个原始对象导致了此次问题的发生。

解决方案1:给 tPartnerOrgService 加上@Lazy注解

解决方案2:代码优化,不要让@Async的Bean参与循环依赖

四、针对以上问题对Spring如何解决循环依赖进行详细阐述

首先Spring维护了三个Map,也就是我们通常说的三级缓存

  • singletonObjects:俗称单例池,缓存创建完成的单例
  • BeansingletonFactories:映射创建Bean的原始工厂
  • earlySingletonObjects:映射Bean的早期引用,也就是说这个Map里的Bean不是完整的,只是完成了实例化,但还没有初始化

Spring通过三级缓存解决了循环依赖,其中一级缓存为单例池(singletonObjects),二级缓存为早期曝光对象earlySingletonObjects,三级缓存为早期曝光对象工厂(singletonFactories)。

当A、B两个类发生循环引用时,在A完成实例化后,就使用实例化后的对象去创建一个对象工厂,并添加到三级缓存中,如果A被aop代理,那么通过这个工厂获取到的就是A代理后的对象,如果A没有被AOP代理,那么这个工厂获取到的就是A实例化的对象。

当A进行属性注入时,会去创建B,同时B又依赖了A,所以创建B的同时又会去调用getBean(a)来获取需要的依赖,此时的getBean(a)会从缓存中获取,第一步,先获取到三级缓存中的工厂;第二步,调用对象工工厂的getObject方法来获取到对应的对象,得到这个对象后将其注入到B中。

紧接着B会走完它的生命周期流程,包括初始化、后置处理器等。当B创建完后,会将B再注入到A中,此时A再完成它的整个生命周期。至此,循环依赖结束!

简单一句话说:先去缓存里找Bean,没有则实例化当前的Bean放到Map,如果有需要依赖当前Bean的,就能从Map取到。

针对上面的@Aysnc注解产生的循环依赖进行分析:

有@Aysnc注解的bean最后生成了一个代理对象,我们结合Spring bean创建的流程来分析这次问题。

  • beanA开始初始化,beanA实例化完成后给beanA的依赖属性beanB进行赋值
  • beanB开始初始化,beanB实例化完成后给beanB的依赖属性beanA进行赋值
  • 因为beanA是支持循环依赖的,所以可以在earlySingletonObjects中可以拿到beanA的早期引用的,但是因为beanB打了@Aysnc注解并不能在earlySingletonObjects中可以拿到早期引用
  • 接下来执行执行initializeBean(Object existingBean, String beanName)方法,这里beanA可以正常实例化完成,但是因为beanB打了@Aysnc注解,所以向Spring ioc容器中增加了一个代理对象,也就是说beanAbeanB并不是一个原始对象,而是一个代理对象
  • 接下来进行执行doCreateBean方法时对进行检测,以下代码有所删减,只保留核心逻辑代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					// 重点在这里,这里会遍历所有依赖的bean,如果beanA依赖beanB和缓存中的beanB不相等
					// 也就是说beanA本来依赖的是一个原始对象beanB,但是这个时候发现beanB是一个代理对象,就会增加到actualDependentBeans
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					// 发现actualDependentBeans不为空,就发生了我们最开始截图的错误
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] 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.");
					}
				}
			}
		}
		// ReGISter bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}
		return exposedObject;
	}

到此这篇关于Springboot详细讲解循环依赖的文章就介绍到这了,更多相关Springboot循环依赖内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Springboot详细讲解循环依赖

本文链接: https://www.lsjlt.com/news/151680.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Springboot详细讲解循环依赖
    目录一、循环依赖二、循环依赖形成条件(使用构造器注入)三、循环依赖形成条件(@Aysnc注解的bean生成了对象的代理)四、针对以上问题对Spring如何解决循环依赖进行详细阐述一、...
    99+
    2022-11-13
  • JavaSpring处理循环依赖详解
    目录01-前言:什么是循环依赖?02-Spring 如何处理循环依赖?03-Spring 中解决循环依赖的三级缓存01-前言:什么是循环依赖? 首先,我们先明确下依赖的定义。 如果一...
    99+
    2023-05-17
    Java中的Spring Spring处理循环依赖
  • springboot怎么解决循环依赖问题
    在Spring Boot中解决循环依赖问题,可以尝试以下几种方法:1. 使用构造器注入:将循环依赖的对象注入到构造器中,并且使用`@...
    99+
    2023-09-27
    springboot
  • 关于SpringBoot禁止循环依赖解说
    前言: Spring的Bean管理,一直是整个体系中津津乐道的东西。尤其是Bean的循环依赖,更是很多面试官最喜欢考察的2B知识点之一。 但事实上,项目中存在Bean的循环依赖,是代...
    99+
    2022-11-13
  • Spring循环依赖的解决方案详解
    目录简介方案1. Feild注入单例(@AutoWired)方案2. 构造器注入+@Lazy方案3. Setter/Field注入单例方案4. @PostConstruct方案5. ...
    99+
    2022-11-13
  • springboot解决循环依赖的方法有哪些
    在Spring Boot中,解决循环依赖的方法主要有以下几种:1. 使用构造函数注入:将循环依赖的Bean,通过构造函数的方式注入到...
    99+
    2023-09-17
    springboot
  • SpringBoot循环依赖的症状和解决方案
    目录什么是循环依赖?问题及症状ComponentAComponentB错误解决方法构造器注入的案例延迟注入的案例接口隔离的案例什么是循环依赖? 循环依赖是指在Spring Boot ...
    99+
    2023-05-15
    Java SpringBoot循环依赖 SpringBoot循环依赖 解决SpirngBoot循环依赖
  • Java详细讲解依赖注入的方式
    目录Spring中的三种依赖注入方式可能遇到的问题Spring中的三种依赖注入方式 Field Injection :@Autowired注解的一大使用场景就是Field Injec...
    99+
    2022-11-13
  • 浅入浅出的讲解Spring循环依赖问题
    目录前言概念什么是循环依赖?报错信息通俗版理解两人对峙必须有一人妥协Spring版理解实例化和初始化什么区别?三级缓存创建过程(简易版)创建过程(源码版)最后前言 最近有粉丝...
    99+
    2022-11-12
  • SpringBoot循环依赖问题实例分析
    本文小编为大家详细介绍“SpringBoot循环依赖问题实例分析”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot循环依赖问题实例分析”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。简介说明本文介...
    99+
    2023-07-02
  • SpringBoot禁止循环依赖实例分析
    这篇文章主要讲解了“SpringBoot禁止循环依赖实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot禁止循环依赖实例分析”吧!前言:Spring的Bean管理,一直...
    99+
    2023-06-30
  • Java Spring 循环依赖解析
    目录1、常见问题2、什么是循环依赖?3、循环依赖说明4、BeanCurrentlyInCreationException5、依赖注入的两种方式方式一:构造器方式注入依赖方式二:以 s...
    99+
    2022-11-13
  • Spring循环依赖之问题复现详解
    目录简介问题复现1.构造器注入2.Feild注入多例(@AutoWired) 3.Setter注入多例(@AutoWired) 解决方案简介 说明 本文介绍Spr...
    99+
    2022-11-13
  • 深度解析SpringBoot中@Async引起的循环依赖
    目录事故时间线猜想什么是循环依赖什么是@Async啊,昨晚发版又出现了让有头大的循环依赖问题,按理说Spring会为我们解决循环依赖,但是为什么还会出现这个问题呢?为什么在本地、UA...
    99+
    2022-11-13
  • Java中的Spring循环依赖详情
    目录一、什么是循环依赖?那么循环依赖是个问题吗?二、Bean的生命周期三、三级缓存解决循环依赖思路分析四、Spring到底解决了哪种情况下的循环依赖五、总结一、什么是循环依赖? 很简...
    99+
    2022-11-13
  • Spring怎么解决循环依赖
    本篇内容介绍了“Spring怎么解决循环依赖”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!写在前面最近,在...
    99+
    2022-10-19
  • Spring轻松解决循环依赖
    目录解决循环依赖的原理源码解析总结Spring 框架是一个流行的Java应用程序框架,它提供了许多强大的功能,如依赖注入和面向切面编程。然而在使用 Spring 框架时,我们可能会遇...
    99+
    2023-05-16
    Spring循环依赖怎么解决 Spring循环依赖
  • java循环依赖如何解决
    在Java中,循环依赖是指两个或多个类之间存在相互依赖关系,导致无法编译或运行的情况。解决循环依赖的方法可以有以下几种: 重构代...
    99+
    2023-10-23
    java
  • spring循环依赖策略解析
    循环依赖所谓循环依赖就是多个Bean之间依赖关系形成一个闭环,例如A->B->C->...->A 这种情况,当然,最简单的循环依赖就是2个Bean之间互相依赖:A->B(A依赖B), B->A(B依赖A)...
    99+
    2023-05-31
    spring 循环 依赖策略
  • 怎么理解Spring循环依赖
    本篇内容介绍了“怎么理解Spring循环依赖”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!通常来说,如果问Spring内部如何解决循环依赖,...
    99+
    2023-06-16
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作