最易懂Spring循环依赖

Spring源码:循环依赖】一文弄懂Spring循环依赖 1. 什么是循坏依赖 很简单,其实就是互相依赖对方,比如,有一个A对象依赖了B对象,B对象又依赖了A对象。 // A依赖了B public class A{ private B b; } // B依赖了A public class B{ private A a; } 但是,在我们普通的java开发中,循坏依赖会出现问题吗? 如果不考虑Spring循环依赖并不是问题,因为对象之间相互依赖注入是很正常的事情。 比如: 这样,A,B就互相依赖上了。 但是,在Spring 阅读详情

前言

了解Spring循环依赖和三级缓存需要熟悉IOCAOP流程。

工作中常用new语句创建对象,通过new方法创建的对象是没有属性填充的,而Spring创建对象时可指定对象的生命周期;

说Spring的bean默认是单例的是因为Spring启动时只会生成单例对象放入单例池,即singletonBeanRegistry,而使用@Scope("prototype")注解标注的类是不会加载进单例池中的。

不理解spring注入方式的同学可以先看往期这篇:[Spring Dependency Injection]

观看本篇需要熟悉getBean流程:[ 简单理解Spring getBean流程]

介绍

循环依赖就是循环引用,指两个或则两个以上的bean互相依赖对方,最终形成闭环。比如“A对象依赖B对象,而B对象也依赖A对象”。

SpringIOC中分为两种情况

  1. 普通的Bean死循环创建
  2. 创建的Bean被AOP代理

Spring解决循环依赖的前提:

  1. 只支持单例对象。原型prototype的场景如果循环依赖就会造成无限套娃,所以是不被支持的,spring会抛出异常。 我们谈的循环依赖都是依据单例对象相互依赖产生的循环依赖问题。

  2. 不支持构造构造器注入的循环依赖(这里说的是A、B对象均采用构造方法注入)。

熟悉依赖注入方式的应该清楚,构造器注入是通过构造方法来生成对象,其必须要先获取属性,才能生成调用构造方法进行实例化,这种情况的循环依赖是无法解决的。

属性注入和setter注入时是需要使用autowried的,而构造器注入是不需要的。

熟悉autowried底层应该清楚,autowired是在实例化后、初始化完成前调用后置处理器从IOC容器中拿到bean通过反射来为对象属性赋值的。

网上找了一张图来说明A、B对象依赖注入方式不同时spring能否解决循环依赖。

非aop循环依赖

通过调用栈可以看出解决循环依赖的关键是在A对象填充属性前将一个匿名内部类ObjectFactory对象放在SingletonFactory(三级缓存)中,在有依赖对象A的对象B填充属性A时通过getSingleton方法的ObjectFactory.getObject() 直接调用内部类中专门用来获取A半成品对象的getEarlyBeanReference方法,从而完成填充属性。

    protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
        Object exposedObject = bean;
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            for (BeanPostProcessor bp : getBeanPostProcessors()) {
                if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                    SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                    exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
                }
            }
        }
        return exposedObject;
    }

getEarlyBeanReference方法则会循环调用bean后置处理器的getEarlyBeanReference方法,非aop情况下,会调用两个后置处理器,其都是直接返回传参的bean,未做处理。

aop循环依赖

此处不讲解AOP如何生成代理对象,在下篇文章会进行讲解

在aop代理的情况下,则getEarlyBeanReference方法中会多出一个后置处理器;

在调用bean后置处理器的getEarlyBeanReference方法中,会通过wrapIfNecessary生成代理对象。

    // Aop提前引用入口
    public Object getEarlyBeanReference(Object bean, String beanName) {
        Object cacheKey = getCacheKey(bean.getClass(), beanName);
        this.earlyProxyReferences.put(cacheKey, bean);
        return wrapIfNecessary(bean, beanName, cacheKey);
    }

熟悉AOP的应该清楚,aop代理对象是在初始化那一步的后置处理器的postProcessAfterInitialization方法中生成代理对象的,同样是wrapIfNecessary方法,和上面的getEarlyBeanReference方法都出自AbstractAutoProxyCreator类。

    //AOP 创建代理对象入口
    public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
        if (bean != null) {
            Object cacheKey = getCacheKey(bean.getClass(), beanName);
            //如果没有被提前代理过
            if (this.earlyProxyReferences.remove(cacheKey) != bean) {
                //最终会调用createProxy,创建代理bean
                return wrapIfNecessary(bean, beanName, cacheKey);
            }
        }
        return bean;
    }
Hypermesh二次开发实战:Tcl命令分类与常用函数详解(附避坑指南) 本文深入解析Hypermesh二次开发中Tcl命令的三大核心类别:界面命令、查询命令与修改命令。重点剖析了*createmark集合管理与hm_getvalue信息查询等关键函数的实战用法,并提供了避免Mark覆盖、生命周期管理等常见陷阱的实用指南,旨在帮助CAE工程师构建高效可靠的自动化前处理流程。 阅读详情

相关推荐

机械臂算法设计MATLAB|运动学动力学|轨迹规划|路径规划|Simulink

RRT为常用的路径规划算法,还有其变种(RRT*,RRT-connect等)。RRT是一种多维空间中高效的规划方法。它以一个初始点作为根节点,通过随机采样增加叶子节点的方式,生成一个随机扩展树。随机扩展树不断增长,直到到达目的位置。**Step1:**构建多维状态空间(joint space),**Step2:**构建joint space的障碍检测算法**Step3:**在joint space应用RRT。

qq_35997213的博客 4435

图解Spring循环依赖,看过之后再也不怕面试被问到了!

作者:Vtjuejin.im/post/5e927e27f265da47c8012ed9前言Spring如何解决的循环依赖,是近两年流行起来的一道Java面试题。其实笔者本人对这类框架源...

Java知音 1252

PML二次开发之宏和函数.pdf

PML语言概述– 基本编码惯例– PML如何与设计模型交互– 窗口和菜单如何与PML一起作用第一天 -基本语法PML1/PML2– 第二天 - PML2

详解Spring循环依赖

代理对象的创建时机,aspectj与advisor的关系,自动后置代理处理器(annotationAwareAspectJAutoProxyCreator),set注入的循环依赖spring的三级缓存详解,构造注入的循环依赖以及相关的解决方案等等。

weixin_53142722的博客 1253

面试官:烂大街的 Spring 循环依赖问题你都不会,我怎么敢录用你

在关于Spring的面试中,我们经常会被问到一个问题:Spring是如何解决循环依赖的问题的。 这个问题算是关于Spring的一个高频面试题,因为如果不刻意研读,相信即使读过源码,面试者也不一定能够一下子思考出个中奥秘。本文主要针对这个问题,对其实现原理进行深入分析! 什么是循环依赖? 举个例子 /** * A 类,引入 B 类的属性 b */ public class A { private B b; } /** * B 类,引入 A 类的属性 a */ public class B {

Java-面试 953

Spring循环依赖,简明易懂,只看这一篇就够啦

我们知道Spring的AOP实现在bean初始化(而非实例化)之后,如果 A 的原始对象注入给 B 的属性之后,A 的原始对象进行了 AOP 产生了一个代理对象,此时就会出现,对于 A 而言,它的 Bean 对象其实应该是 AOP 之后的代理对象,而 B 的 a 属性对应的并不是 AOP 之后的代理对象,这就产生了冲突。2:A在属性填充时发现自己需要B对象,但是在三级缓存中均未发现B,于是创建B的半成品,存在于第3级缓存singletonFactories。

weixin_45458335的博客 225

解决spring循环依赖的源码解析

spring循环依赖的解决

weixin_45999801的博客 2619

spring循环依赖及解决方法

一、三种循环依赖的情况 ①构造器的循环依赖:这种依赖spring是处理不了的,直接抛出BeanCurrentlylnCreationException异常。 ②单例模式下的setter循环依赖:通过“三级缓存”处理循环依赖,能处理。 ③非单例循环依赖:无法处理。原型(Prototype)的场景是不支持循环依赖的,通常会走到AbstractBeanFactory类中下面的判断,抛出异常。 if (isPrototypeCurrentlyInCreation(beanName)) { throw new

cristianoxm的博客 4万+

Spring三级缓存解决循环依赖

1. 前言 循环依赖:就是N个类循环(嵌套)引用。 通俗的讲就是N个Bean互相引用对方,终形成闭环。用一副经典的图示可以表示成这样(A、B、C都代表对象,虚线代表引用关系): 其实可以N=1,也就是极限情况的循环依赖:自己依赖自己 这里指的循环引用不是方法之间的循环调用,而是对象的相互依赖关系。(方法之间循环调用若有出口也是能够正常work的) 2. Spring Bean的...

傅红雪的专栏 2万+

Spring如何解决循环依赖

烂大街的Spring循环依赖该如何回答? 什么是循环依赖? 从字面上来理解就是A依赖B的同时B也依赖了A,就像上面这样,或者C依赖与自己本身。体现到代码层次就是这个样子 @Component public class A { // A中注入了B @Autowired private B b; } --- @Component public class B { // B中注入了A @Autowired private A a; } --- // 自己依赖自己 @Component public c

意田天的博客 2万+

SpringSpring循环依赖以及解决方案

Spring循环依赖指的是两个或多个Bean之间相互依赖,形成一个环状依赖的情况。通俗的说,就是A依赖B,B依赖C,C依赖A,这样就形成了一个循环依赖的环。​ Spring循环依赖通常会导致Bean无法正确地被实例化,从而导致应用程序无法正常启动或者出现异常。因此,Spring循环依赖是一种需要尽量避免的情况。

长夜烛火的博客 7973

spring 如何解决循环依赖

spring 如何解决循环依赖

快乐的小三菊的博客 3925

SpringSpring循环依赖及解决方案

Spring框架中,循环依赖是一个非常常见的问题。当两个或多个bean之间相互依赖时,就会产生循环依赖。这种情况可能会导致程序无限循环,从而导致性能问题和程序崩溃。Spring框架通过检测循环依赖并采取相应措施来解决这个问题。例如,使用懒加载的方式来避免循环依赖。但是,有时候我们的代码中可能会有一些错误,导致循环依赖的产生。在这篇博客中,我们将深入探讨Spring循环依赖的问题。我们将讨论如何产生循环依赖,以及如何避免和解决循环依赖。我们还将深入探讨Spring框架如何检测和解决循环依赖

qq_46096136的博客 9454

spring如何解决循环依赖

这里我们主要分析Spring bean的循环依赖,以及Spring的解决方式。 通过这种解决方式,我们可以应用在我们实际开发项目中。1、什么是循环依赖? 2、怎么检测循环依赖 3、循环依赖的N种场景 3、Spring怎么解决循环依赖 4、Spring对于循环依赖无法解决的场景 5、Spring解决循环依赖的方式我们能够学到什么?循环依赖其实就是循环引用,也就是两个或则两个以上的bean互相持有对方,终形成闭环。比如A依赖于B,B依赖于C,C又依赖于A。如下图: 注意,这里不是函数的循环调用,是对象的相互依

m0_67393827的博客 8687

Spring循环依赖

循环依赖,其实就是循环引用,就是两个或者两个以上的 Bean 互相引用对方,终形成一个闭环,如 A 依赖 B,B 依赖 C,C 依赖 A。结果:需要注意的是本例中启动时是不会报错的(因为非单例Bean默认不会初始化,而是使用时才会初始化),所以很简单咱们只需要手动。对于构造器注入出现缓存依赖,Spring 是无法解决的,因为当前 Bean 还未实例化,无法提前暴露对象,所以只能抛出异常。)​:存储Bean的ObjectFactory,用于创建早期的Bean实例。

qq_40463629的博客 2136

Spring之IOC循环依赖问题

Spring IOC循环依赖问题 1. 什么是循环依赖 循环依赖其实就是循环引⽤,也就是两个或者两个以上的 Bean 互相持有对⽅,终形成闭环。⽐如A依赖于B,B又依赖于A。套娃模式无限循环。这⾥不是函数的循环调⽤,是对象的相互依赖关系。循环调⽤其实就是⼀个死循环,除⾮有终结条件。 2. Spring循环依赖场景有哪些 1. 构造器的循环依赖(构造器注⼊) 2. Field 属性的循环依赖(set注⼊) 3. Spring是如何处理循环依赖的 1. 构造器的循环依赖无法解决 ​ 因为构造器要调用构造函

杜莱的博客 436

面试必杀技,讲一讲Spring中的循环依赖

前言 Spring中的循环依赖一直是Spring中一个很重要的话题,一方面是因为源码中为了解决循环依赖做了很多处理,另外一方面是因为面试的时候,如果问到Spring中比较高阶的问题,那么循环依赖必定逃不掉。如果你回答得好,那么这就是你的必杀技,反正,那就是面试官的必杀技,这也是取这个标题的原因,当然,本文的目的是为了让你在之后的所有面试中能多一个必杀技,专门用来绝杀面试官! 本文的核心思想就是, 当面试官问: “请讲一讲Spring中的循环依赖。”的时候, 我们到底该怎么回答? 主要分下面几点 什么是循环依

bishe_teacher的博客 183

图解 Spring 循环依赖,写得太好了!

作者 |Vt来源 |https://urlify.cn/jymi2qSpring如何解决的循环依赖,是近两年流行起来的一道Java面试题。其实笔者本人对这类框架源码题还是持一定的怀疑...

程序员闪充宝 517

Spring为何需要三级缓存解决循环依赖,而不是二级缓存?

今天给大家分享一道大厂面试真题,Spring为何需要三级缓存解决循环依赖,而不是二级缓存?我一共分为五个部分来给大家介绍: 1、什么是循环依赖循环依赖就是指循环引用,是两个或多个Bean相互之间的持有对方的引用。在代码中,如果将两个或多个Bean互相之间持有对方的引用,因为Spring中加入了依赖注入机制,也就是自动给属性赋值。Spring给属性赋值时,将会导致死循环。那么,哪些情况会出现循环依赖呢? 2、哪些情况会出现循环依赖循环依赖有三种形态: 1、相互依赖,也就是A 依赖 B,B 又依赖 A,

Tom弹架构 4670

通俗解释spring是如何解决循环依赖

spring解决的是bean属性的循环依赖,bean的初始化一般要经过实例化、属性赋值、初始化三个过程之后才能被spring使用的。循环依赖其实是发生在属性赋值的阶段。 spring是通过三级缓存去解决循环依赖的问题的,三级缓存其实就是其实就是spring在初始化bean的过程中三个不同的存放不同时期的bean的三个map。分别存放完整的bean、提前曝光的半成品bean、和半成品bean 它们分别是singletonObjects,earlySingletonObjects,以及singletonFact

weixin_39650169的博客 394
上一篇: 简单理解Spring getBean流程
下一篇: 深入理解Sping AOP(一)
chenxuyuana
博客等级 码龄4年 285粉丝 257原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值