• Spring--如何解决循环依赖


    利用三级缓存解决,三级缓存都是什么?

    一级缓存:singletonObjects,存放可用的成品Bean

    二级缓存:earlySingletonObjects,存放半成品的Bean半成品的Bean是已创建对象,但是未注入属性和初始化。用以解决循环依赖。

    三级缓存:存的是Bean工厂对象,用来生成半成品的Bean并放入到二级缓存中。用以解决循环依赖。(会将需要被增强的类,提前增强。添加AOP缓存,后续通过这个缓存判断是否被增强,保证不重复增强。)

    如何解决循环依赖?

    1. 通过构建函数创建A对象(A对象是半成品,还没注入属性和调用init方法)。
    2. A对象需要注入B对象,发现缓存里还没有B对象,将半成品对象A放入半成品缓存
    3. 通过构建函数创建B对象(B对象是半成品,还没注入属性和调用init方法)。
    4. B对象需要注入A对象,从半成品缓存里取到半成品对象A
    5. B对象继续注入其他属性和初始化,之后将完成品B对象放入完成品缓存
    6. A对象继续注入属性,从完成品缓存中取到完成品B对象并注入。
    7. A对象继续注入其他属性和初始化,之后将完成品A对象放入完成品缓存

    为什么构造器注入属性的时候不能解决循环依赖问题?

      Spring注入单例bean时,实例化和初始化是分开的,将提前实例化好的对象提前暴露出去,供别人使用。使用构造器的时候,必须要用构造方法,没有构造方法无法完成对象的实例化操作,无法创建对象,会陷入死循环中。

    一级缓存能不能解决此问题?

      不能。如果只有一级缓存,初始化完成和未初始化完成的对象都放在这个map中,拿到的可能是没有初始化的,会造成空指针异常。

    二级缓存能不能解决此问题?

      可以解决。但是,注入的对象实现了AOP(比如:代理对象),那么注入到其他bean的时候,不是最终的代理对象,而是原始的。通过三级缓存的ObjectFactory才能实现类最终的代理对象。

      解决方案: 在提前曝光半成品时,直接执行getEarlyBeanReference创建到代理,并放入到缓存earlySingletonObjects中。那就不需要通过ObjectFactory延迟执行getEarlyBeanReference,也就不需要singletonFactories这一级缓存。

      spring为什么不这么做?

      如果要使用二级缓存解决循环依赖,意味着Bean在构造完后就创建代理对象,这样违背了Spring设计原则

      Spring结合AOP跟Bean的生命周期,是在Bean创建完全之后通过AnnotationAwareAspectJAutoProxyCreator这个后置处理器来完成的,在这个后置处理的postProcessAfterInitialization方法中对初始化后的Bean完成AOP代理。

      如果出现了循环依赖,那没有办法,只有给Bean先创建代理,但是没有出现循环依赖的情况下,设计之初就是让Bean在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。

  • 相关阅读:
    第十二篇 -- 如何向MFC对话框添加菜单
    第十一篇 -- 如何实现MFC窗口的最大化以及控件随最大化
    第二十三篇 -- 学习第二十四天打卡20190715
    第十篇 -- 学习C++宝典2005版
    第二十二篇 -- 学习第二十一天打卡20190711
    修改nginx日志格式为json
    centos7 脚本搭建SVN
    jenkin、SVN、archery集成openLDAP
    centos搭建OPENldap
    matomo 开源网站分析平台
  • 原文地址:https://www.cnblogs.com/BounceGuo/p/14108399.html
Copyright © 2020-2023  润新知