一、Spring bean生命周期

可以簡化為以下5步。
1、構(gòu)建BeanDefinition
2、實例化 Instantiation
3、屬性賦值 Populate
4、初始化 Initialization(BeanPostprocessor -> Aware,init)
5、銷毀 Destruction
二、Spring 三級緩存作用
2.1、一級緩存
/** Cache of singleton objects: bean name to bean instance. */
Map<String, Object> singletonObjects;
用來保存實例化、初始化都完成的bean對象。
2.2、二級緩存
/** Cache of early singleton objects: bean name to bean instance. */
Map<String, Object> earlySingletonObjects ;
用來保存實例化完成,但是未初始化完成的對象(這個對象不一定是原始對象,也有可能是經(jīng)過AOP生成的代理對象)。
2.3、三級緩存
/** Cache of singleton factories: bean name to ObjectFactory. */
Map<String, ObjectFactory<?>> singletonFactories;
用來保存一個對象工廠(ObjectFactory),提供一個匿名內(nèi)部類,用于創(chuàng)建二級緩存中的對象。
三級緩存中提到的ObjectFactory即 () -> getEarlyBeanReference(beanName,mbd,bean),其中bean就是原始對象。
其中getEarlyBeanReference 方法是 SmartInstantiationAwareBeanPostProcessor接口中定義的,AbstractAutoProxyCreator(Spring AOP proxy creator)實現(xiàn)了該方法。


三、Spring三級緩存實現(xiàn)
3.1、獲取beanName:A
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(beanName:A)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(beanName:A)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(beanName:A, allowEarlyReference:true)
分別按照一級緩存、二級緩存、三級緩存順序加載。如果存在循環(huán)依賴(比如beanName:B依賴beanName:A),而且三級緩存中存在beanName:A的引用,則從三級緩存中拿到beanName:A對應(yīng)的提早曝光的對象(可能是原始對象,也可能是代理對象)并放入二級緩存。比如又有beanName:C依賴beanName:A,會直接從二級緩存中獲取到。

3.2、bean創(chuàng)建和初始化完成
org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean(beanName:A)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(beanName:A, ObjectFactory:lamda表達,調(diào)用AbstractBeanFactory#createBean(beanName:A))
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingleton(beanName:A,singletonObject:A)
直接添加到一級緩存

3.3、bean創(chuàng)建完成之后
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#createBean(beanName:A, RootBeanDefinition:mbd, Object[]:args)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean(beanName:A, RootBeanDefinition:mbd, Object[]:args)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#addSingletonFactory(beanName:A, () -> getEarlyBeanReference(beanName:A, mbd, bean:A))
//放入三級緩存,beanName:A -> ObjectFactory( () -> getEarlyBeanReference(beanName:A, mbd, bean:A) )
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean //屬性填充
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean //初始化

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
}
}
}
}
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(beanName:A, allowEarlyReference:false)
四、一個簡單的A、B互相依賴循環(huán)依賴場景

五、@Async注解循環(huán)依賴報錯
@Transactional使用的是自動代理創(chuàng)建器AbstractAutoProxyCreator,它實現(xiàn)了getEarlyBeanReference()方法從而很好的對循環(huán)依賴提供了支持。
@Async的代理創(chuàng)建使用的是AsyncAnnotationBeanPostProcessor單獨的后置處理器實現(xiàn)的,它只在一處postProcessAfterInitialization()實現(xiàn)了對代理對象的創(chuàng)建,因此若出現(xiàn)它被循環(huán)依賴了,就會報BeanCurrentlyInCreationException。
protected Object doCreateBean( ... ){
...
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
...
Object exposedObject = bean;
/**
*假如A實例有方法注有@Async注解,A實例依賴B實例,B實例依賴A實例。創(chuàng)建A實例時先走到populateBean方法,然后開始填充屬性B實例,B實例也會走到populateBean方法,然后從三級緩存中通過A流程中的getEarlyBeanReference()方法,從而拿到A的早期引用*。執(zhí)行A的getEarlyBeanReference()方法的時候,會執(zhí)行自動代理創(chuàng)建器,這里最終得到是可能是原始A對象,也可能是代理后的A對象(注意哦,A實例的@Async注解這里還沒有被處理呢)。exposedObject此時指向的是原始A實例。
*/
populateBean(beanName, mbd, instanceWrapper);
/**
*標(biāo)注有@Async的A實例的代理對象在此處會被生成, 參照類:AsyncAnnotationBeanPostProcessor。執(zhí)行完之后,exposedObject指向的是個代理對象而非原始A實例了。
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
...
// 這里是報錯的重點。
if (earlySingletonExposure) {
/**
*因為A被B循環(huán)依賴進去了,所以此時A是被放進了二級緩存的,所以此處earlySingletonReference指向的是通過創(chuàng)建A實例流程中的getEarlyBeanReference()返回的A實例(再強調(diào)用一下,可能是原始對象,也可能是代理對象)。
*說到這里,什么情況下earlySingletonReference==null?也就是getSingleton(beanName:A, false)==null,只有當(dāng)A實例沒有牽涉到循環(huán)依賴的時候(即不存在A依賴B且B依賴A的場景;單獨存在B依賴A是沒有問題,A的三級緩存根本不會執(zhí)行,所以二級緩存就不會有值,A創(chuàng)建并初始化完成之后直接放到了一級緩存)。
*/
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
//這里exposedObject指向的是被@Aysnc代理過的對象,而bean是原始對象,所以此處不相等,走else邏輯。
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
/**
*allowRawInjectionDespiteWrapping 標(biāo)注是否允許此Bean的原始類型被注入到其它Bean里面,即使自己最終會被包裝(代理)。
*默認(rèn)是false表示不允許,如果改為true表示允許,就不會報錯啦。這是我們后面講的決方案的其中一個方案。
*另外dependentBeanMap是記錄著每個Bean它所依賴的Bean的Map。
*/
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
//因為A依賴于B,所以此處拿到了B實例的beanName
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
/**
*B實例經(jīng)過removeSingletonIfCreatedForTypeCheckOnly最終返返回false 因為alreadyCreated里面已經(jīng)有它了表示B已經(jīng)完全創(chuàng)建完成了。
*既然B實例已經(jīng)創(chuàng)建完成了,通過創(chuàng)建A實例流程中的getEarlyBeanReference()返回的A實例已經(jīng)注入到了B實例中,此時B實例注入的和exposedObject指向的不是同一個A實例,那肯定就有問題了。
*/
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
// 若存在這種真正的依賴,那就報錯了~~~ 則個異常就是上面看到的異常信息
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
...
}
具體原因分析參考:https://blog.csdn.net/f641385712/article/details/92797058
六、總結(jié)
1、Spring 解決循環(huán)依賴有兩個前提條件:不全是構(gòu)造器方式的循環(huán)依賴,必須是單例。
2、如果沒有出現(xiàn)循環(huán)依賴,第三級緩存(singletonFactories)將不會使用到,對象會按照Spring創(chuàng)建bean的生命周期流程,最后將bean直接放到第一級緩存(singletonObjects)中。
3、一定要三級緩存嘛,二級緩存不能解決循環(huán)依賴?不能,主要是為了生成代理對象。
因為三級緩存中放的是生成具體對象的匿名內(nèi)部類(ObjectFactory),它可能生成代理對象,也可能是普通的實例對象。使用三級緩存主要是為了保證不管什么時候使用的都是一個對象。假設(shè)只有二級緩存的情況,往二級緩存中放的顯示一個普通的Bean對象,BeanPostProcessor去生成代理對象之后,覆蓋掉二級緩存中的普通Bean對象,無法保證程多線程環(huán)境下獲取到bean對象一致性。