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在生命周期的最后一步完成代理而不是在实例化后就立马完成代理。

 

posted @ 2020-12-09 14:32  蹦蹦郭  阅读(262)  评论(0编辑  收藏  举报