Spring的循环依赖问题始终是中高级Java高频面试题之一,其中的考点就在于你对Spring中bean的加载过程是否有肯定的了解。

那么咱们就以下几点说一下。

Spring中罕用的注入形式有哪几种?

结构器注入

set办法注入

注解注入

对于这方面的常识之后再细聊,明天重点不是这些。

什么是循环依赖?

循环依赖,留神,这里说的是依赖,而不是调用,这是两个概念,肯定不要混同。

循环依赖从字面意思来看,就是A依赖B,而后B依赖A,当然,这个依赖过程也能够更长,不肯定就非要两个相互依赖,十个八个也是循环依赖,只有造成了一个闭环。

如图,这样就造成了一个闭环,简略说,如此依赖上来,就是一个死循环。

如何解决循环依赖?

Spring中的循环依赖包含两种,结构器循环依赖和setter循环依赖。

结构器循环依赖

当应用结构器注入形式时,Spring是无奈解决循环依赖的,在出问题时会报错,抛出BeanCurrentlyInCreationException异样。

模仿一下场景的话,大略如下:

  1. X1在创立时,发现结构器须要X2类对象,只能去创立X2;
  2. X2在创立时,又发现结构器须要X3类对象,只能去创立X3;
  3. X3在创立时,又再次发现结构器须要X1对象;周而复始,最终抛出异样。

setter循环依赖

次要来说一下setter循环依赖,通过Spring在创立bean时的一级、二级、三级缓存的概念解决的。

留神:这里解决的只是单例模式下的setter循环依赖,非单例模式下的仍然没有方法解决,在业务环境中该当尽量避免此类情况。

创立Bean的缓存概念:

一级缓存:singletonObjects,能够称为成品池,寄存齐全实例化属性赋值实现的Bean,间接能够应用。

二级缓存:earlySingletonObjects,能够称为半成品池,寄存晚期Bean的援用,尚未属性拆卸的Bean

三级缓存:singletonFactories,能够称为工厂池,寄存实例化实现的Bean工厂。

通过setter注入时,会经验以下几个过程。

看图谈话!

1)X1在创立时,首先依据构造函数创立bean,裸露一个Factory给三级缓存(工厂池),并且将其放入二级缓存(半成品池);而后进行属性的拆卸,发现有依赖关系,查问三级缓存是否存在,如没有,返回创立。

2)创立X2时,同X1,返回创立X3。

3)创立X3时,这时三级缓存中曾经存在X1,即可间接注入,而后将X3的bean对象放入一级缓存(成品池)。

4)随后X2、X1顺次能够创立实现,并且放入一级缓存中。

5)如此就实现setter循环依赖问题的解决,外围就是这个三级缓存。

留神:这里的bean对象创立实现,放入一级缓存中时,会将对应的二级、三级缓存清掉。

本文参加了 SegmentFault 思否征文「如何“反杀”面试官?」,欢送正在浏览的你也退出。