springioc循环依赖问题详解

springioc循环依赖问题详解

循环依赖问题在Spring中主要有三种情况

通过构造方法进行依赖注入时产生的循环依赖问题。 通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。 通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。

注意:在Spring中,只有【第三种方式】的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。

源码中怎么判断出现了循环依赖问题?

对于两种情况:

从创建实例的过程去说,首先根据bd拿到class信息,根据默认或者配置拿到构造方法,然后根据反射调用实例化,下一步就是依赖注入,bean后处理器,围绕着init-method方法==》存在依赖注入的地方有两个,一个是构造方法,一个是构造方法创建实例以后,通过set注入依赖。spring处理依赖的流程是,首先在spring容器中去找,如果没有,根据bd去实例化一个对象。如果依赖的bean没有对应的bd定义,就会直接抛错。

原型循环依赖:假设ab相互依赖,a依赖b;spring为了发现原型依赖,提供了一个threadlocal类型的set方法,在执行创建逻辑的时候,就开始了用来记录当前实例化的beanname;假设原型实例化a时候,发现依赖b,在threadlocal-set中发现了a,在这个地方,先是去看缓存中是否有b可以用,没有的情况下再去实例化b依赖a,会在注入依赖的时候,去看缓存中是否有a,如果没有就会创建一个bean,因为a是prototype原型,就会创建一个新的bean.在创建新的bean之前,会在threadlocal-set中检查是否有a的字符串,如果有就会发现进入了原型循环依赖,这个时候就会抛出异常。因为第一次实例化a的时候,发现依赖b,实例化b的时候,又依赖a,又要实例化a,第二次实例化的时候,发现threadlocal-set中有a,就会抛出这么一个异常。

构造循环依赖:和原型依赖差不多,只不过保存正在创建的bean的set用的不再是threadlocal-set。假设a实例化对象的时候,把正在实例化的beanname 放入到set中,然后执行创建bean对象,执行构造方法,然后通过反射调用构造方法,发现参数中有b,会优先处理构造方法的参数,然后实例化b,发现缓存中没有b,然后就是去构建b,构建b的时候,发现构造方法参数有a,然后通过判断缓存中没有a,又会去实例化a,实例化的时候发现set中有了a,会创建失败,接着spring就会抛出异常了。

普通单实例循环依赖没有问题,是怎么解决的?

spring是依靠三级缓存去解决这个问题的。a和b的例子,假设实例化a,通过a的无参构造方法反射创建实例对象,这个时候的a尚未依赖注入和执行init-method方法,这个对象是一个早期实例会把这个对象先放到三级缓存中去,key是beanname,value是一个objectfactory对象,所以说在处理b依赖a的时候,直接从缓存中拿到a,完成b的实例化,接着处理b对象,完成bean后处理器,init-method方法,然后完成b的实例化以后,会把b放到一级缓存中去,key是beanname,value是b对象。接着会继续走a的实例化流程,并且会把b的引用拿到,处理完a的依赖注入,接着走bean后处理器,和init-method方法。最终a从早期对象升级成为正式对象,也存储到一级缓存中。存之前,会把2、3级缓存中早期对象a清除掉。

细节问题,三级缓存什么时候升级到二级缓存。

a,在getbean方法的时候,会拿到早期实例,在拿到早期实例的前,会把三级缓存中的objectfactory升级到二级缓存中,然后清除掉三级缓存中的objectfactory.

为什么不直接放入到二级缓存中,而是多出一个三级缓存。

总结:多出一级,用于存放aop代理对象。当情景是循环依赖+aop代理的时候,a(a有产生代理的时候)放入第三级缓存的是代理好的对象,b实例化,依赖注入a的时候,直接拿到代理对象a。b实例化,并且完成其他逻辑之后。a继续初始化,a这个时候不是代理对象,会通过检查二级缓存是不是代理对象,是的话,会把真实对象换成代理对象。完成代理逻辑。

综上所述,多一级缓存意义就是在bean循环引用过程中,发生了AOP增强,避免返回真实对象而非代理对象Proxy。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: SpringIoC(Inversion of Control,控制反转)是一种设计模式,它通过将对象的创建和依赖关系的管理交给容器来实现。\[1\]依赖注入(Dependency Injection,DI)是Spring中实现IoC的一种方式,它通过将依赖关系注入到对象中,而不是由对象自己创建或查找依赖。\[2\]Spring提供了三种依赖注入的方式:构造器注入、setter注入和注解注入。构造器注入是通过构造方法来注入依赖,setter注入是通过setter方法来注入依赖,注解注入是通过使用注解(如@Autowired)来注入依赖。\[1\]总的来说,Spring实现IoC的方式是通过提供一个IoC容器来管理Bean,并通过依赖注入的机制来管理Bean之间的依赖关系。\[3\]这样可以实现对象之间的解耦和灵活性,使得代码更易于维护和测试。 #### 引用[.reference_title] - *1* [[Spring] IoC的理解及三种依赖注入方式](https://blog.csdn.net/weixin_43972154/article/details/124103561)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Spring IoC是如何进行依赖注入的](https://blog.csdn.net/yychuyu/article/details/107823395)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值