什么是循环依赖?
很简单,就是A对象依赖了B对象,B对象依赖了A对象
在Spring中,⼀个对象并不是简单new出来了,⽽是会经过⼀系列的Bean的⽣命周期,就是因为 Bean的⽣命周期所以才会出现循环依赖问题。当然,在Spring中,出现循环依赖的场景很多,有的场景 Spring⾃动帮我们解决了,⽽有的场景则需要程序员来解决
Bean的⽣命周期指的就是:在Spring中,Bean是如何⽣成的?
被Spring管理的对象叫做Bean。
Bean的⽣成步骤
Spring扫描class得到BeanDefinition
根据得到的BeanDefinition去⽣成bean
⾸先根据class推断构造⽅法
根据推断出来的构造⽅法,反射,得到⼀个对象(暂时叫做原始对象)
填充原始对象中的属性(依赖注⼊)
如果原始对象中的某个⽅法被AOP了,那么则需要根据原始对象⽣成⼀个代理对象
把最终⽣成的代理对象放⼊单例池(源码中叫做singletonObjects)中,下次getBean时就直接从单例
池拿即可
产生场景
ABean创建-->依赖了B属性-->触发BBean创建--->B依赖了A属性--->需要ABean(但ABean还在创建过程中)
从⽽导致ABean创建不出来,BBean也创建不出来。 这是循环依赖的场景
三级缓存
在Spring中,通过某些机制帮开发者解决了部分循环依赖的问题, 这个机制就是三级缓存,三级缓存是通⽤的叫法。
⼀级缓存为:singletonObjects
⼆级缓存为:earlySingletonObjects
三级缓存为:singletonFactories
A的Bean在创建过程中,在进⾏依赖注⼊之前,先把A的原始Bean放⼊缓存(提早暴露,只要放到缓存了,其他Bean需要时就可以从缓存中拿了),放⼊缓存后,再进⾏依赖注⼊,此时A的Bean依赖了B的Bean,如果B的Bean不存在,则需要创建B的Bean,⽽创建B的Bean的过程和A⼀样,也是先创建⼀个B的原始对象,然后把B的原始对象提早暴露出来放⼊缓存中,然后在对B的原始对象进⾏依赖注⼊A,此时能从缓存中拿到A的原始对象(虽然是A的原始对象,还不是最终的Bean),B的原始对象依赖注⼊完了之后,B的⽣命周期结束,那么A的⽣命周期也能结束。
因为整个过程中,都只有⼀个A原始对象,所以对于B⽽⾔,就算在属性注⼊时,注⼊的是A原始对象,也没有关系,因为A原始对象在后续的⽣命周期中在堆中没有发⽣变化。
注意: