什么是循環(huán)依賴
注冊一個bean對象的過程:
Spring掃描class得到BeanDefinition – 根據(jù)得到的BeanDefinition去生成bean – 現(xiàn)根據(jù)class推斷構(gòu)造方法 – 根據(jù)推斷出來的構(gòu)造方法,反射,得到一個對象 – 填充初始對象中的屬性(依賴注入) – 如果原始對象種的某個方法被AOP了,那么要根據(jù)原始對象生成一個代理對象 – 把最終生成的代理對象放入單例池(singletonObjects,也叫一級緩存)中,下次getBea你就直接從單例池拿
循環(huán)依賴就是在依賴注入的時候相互注入,如
public class AService{
@Autowired
private BService bService;
}
public class BService{
@Autowired
private AService aService;
}
三級緩存過程
Spring使用了三級緩存的策略來解決循環(huán)依賴問題,過程大致如下
創(chuàng)建AService的bean:
因為暫時還沒有BService,所以創(chuàng)建個BService
創(chuàng)建過程中,因為AService已經(jīng)在三級緩存中出現(xiàn)過,所以會進行以下操作
因為BService的屬性都已經(jīng)賦值了,所以BService的初始化就結(jié)束了,可以直接放到一級緩存中,完整過程為:
此時BService已經(jīng)實例化完成,那么AService中的依賴就可以進行注入了:
完整流程圖如下:
簡單的源碼解析
首先在AbstractAutowireCapabaleBeanFactory類里(我是用ctrl+shift+alt+n找到的)的doCreateBean
先創(chuàng)造了一個bean原始對象,此時還沒有依賴注入
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = this.createBeanInstance(beanName, mbd, args);
}
Object bean = instanceWrapper.getWrappedInstance();
然后將lambda表達式放入三級緩存中
if (earlySingletonExposure) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references");
}
//放入三級緩存,這個lambda表達式是為了執(zhí)行aop生成代理對象用的,如果有aop操作,就會拿到代理對象出來
this.addSingletonFactory(beanName, () -> {
return this.getEarlyBeanReference(beanName, mbd, bean);
});
}
緊接著就是A的依賴填充
this.populateBean(beanName, mbd, instanceWrapper);
在這個里面會走到一個getSingleton方法,也就是在緩存中找BService
//allowEarlyReference是是否允許循環(huán)依賴
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && this.isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized(this.singletonObjects) {
//一級緩存中找
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
//二級緩存中找
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
//三級緩存中找
ObjectFactory<?> singletonFactory = (ObjectFactory)this.singletonFactories.get(beanName);
if (singletonFactory != null) { //找到了
//這里相當于上面圖文分析中BService在三級緩存中找到AService
//直接用lambda表達式注冊,然后把他移動到二級緩存中
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
但是顯然AService肯定不會找到,然后就會重新走到createBean,創(chuàng)建一個BService,與A一樣走到上述的getSingleton,這時會在三級緩存中找到A,然后注入
填充完成之后就會把BService放到一級緩存中,移除三級緩存中的B,然后結(jié)束
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
執(zhí)行完整個BService的創(chuàng)建,上面的A的依賴填充才會結(jié)束,然后A也執(zhí)行一遍exposedObject = this.initializeBean(beanName, exposedObject, mbd);這行代碼,A也結(jié)束。文章來源:http://www.zghlxwxcb.cn/news/detail-609256.html
結(jié)合圖文演示看代碼更容易理解捏文章來源地址http://www.zghlxwxcb.cn/news/detail-609256.html
到了這里,關(guān)于[Spring] 三級緩存解決循環(huán)依賴詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!