1.什么是循環(huán)依賴
就是我們的A類依賴(比如@Autowired B b)B類恐疲,這個(gè)時(shí)候我們?nèi)?duì)A類的屬性注入時(shí),我們發(fā)現(xiàn)B可能沒有扯旷,怎么辦拯爽,去實(shí)例化,getBean()钧忽;
但是我在getBean()B的時(shí)候毯炮,我們又發(fā)現(xiàn)A也還沒實(shí)例化完!耸黑!
這個(gè)時(shí)候就A依賴B,B依賴A,就循環(huán)依賴了L壹濉!
2.三級(jí)緩存
//對(duì)于單例模式的Bean整個(gè)IOC容器中只創(chuàng)建一次大刊,不需要重復(fù)創(chuàng)建
Object sharedInstance = getSingleton(beanName);
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
Object singletonObject = this.singletonObjects.get(beanName);
//判斷當(dāng)前單例Bean是否正在創(chuàng)建中为迈,也就是沒有初始化完成
//比如A的構(gòu)造器依賴了B對(duì)象所以得先去創(chuàng)建B對(duì)象, 或則在A的populateBean過程中依賴了B對(duì)象缺菌,得先去創(chuàng)建B對(duì)象葫辐,這時(shí)的A就是處于創(chuàng)建中的狀態(tài)。
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
synchronized (this.singletonObjects) {
//從二級(jí)緩存獲取
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
//從三級(jí)緩存獲取
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
所以一級(jí)緩存為singletonObjects男翰,就是我們的單例對(duì)象工廠的cache
//單例對(duì)象工廠的cache
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);;
如果說另患,我們?cè)谝患?jí)緩存singletonFactories找不到的時(shí)候,并且對(duì)象正在創(chuàng)建中蛾绎,就再?gòu)亩?jí)緩存earlySingletonObjects中獲取
這個(gè)就是我們的二級(jí)緩存 earlySingletonObjects,提前暴光的單例對(duì)象的Cache,也是正在創(chuàng)建中的cache
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
如果還是獲取不到且允許singletonFactories通過getObject()獲取,就從三級(jí)緩存singletonFactory.getObject()(三級(jí)緩存)獲取
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
如果獲取到了我們?cè)購(gòu)娜?jí)緩存移除鸦列,放到二級(jí)緩存租冠!也就是三級(jí)緩存移到二級(jí)緩存
3.三級(jí)緩存賦值
3.1 一級(jí)緩存
doGetBean方法中,Bean實(shí)例化完成后會(huì)調(diào)用getSingleton方法
sharedInstance = getSingleton(beanName, () -> {
try {
//創(chuàng)建一個(gè)指定Bean實(shí)例對(duì)象薯嗤,如果有父級(jí)繼承顽爹,則合并子類和父類的定義
//----------------------------往下走創(chuàng)建Bean-----------------------------------
return createBean(beanName, mbd, args);
}
getSingleton方法中在DefaultSingletonBeanRegistry.java調(diào)用addSingleton()方法
//方法會(huì)加入一級(jí)緩存,同時(shí)清空2.3級(jí)緩存
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
所以骆姐,一級(jí)緩存是存的我們完整的Bean對(duì)象镜粤,就是除了銷毀整個(gè)生命流程結(jié)束了的Bean
3.2 三級(jí)緩存
那么我們3級(jí)緩存是個(gè)什么東西呢?我們可以看下玻褪,它是在哪里put值的肉渴,我們發(fā)現(xiàn),singletonFactories是在
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
賦值带射,而該方法就是在doCreateBean()中調(diào)用同规,但是調(diào)用時(shí)間是在實(shí)例化之后,在populateBean之前!券勺!所以绪钥,三級(jí)緩存為我們實(shí)例化了,但是沒有進(jìn)行DI的一個(gè)半成品的Bean的集合!拟赊!
所以為什么Spring沒有解決構(gòu)造方法的循環(huán)依賴問題锰瘸? 因?yàn)闃?gòu)造方法在實(shí)例化的時(shí)候調(diào)用,所以不會(huì)存到三級(jí)緩存!
1.A實(shí)例化后放入三級(jí)緩存singletonFactories中寸潦,進(jìn)行populateBean,發(fā)現(xiàn)我A依賴B侣灶,并且B是沒有實(shí)例化完成的
2.去實(shí)例化B,發(fā)現(xiàn)B又依賴于A,這個(gè)時(shí)候甸祭,我去一級(jí)緩存獲取A,發(fā)現(xiàn)A也還沒有bean完成,那么我會(huì)繼續(xù)去三級(jí)緩存獲取褥影,發(fā)現(xiàn)了A
3.那么拿到A以后池户,B就能順利的實(shí)例化完成,就算A不是完全的凡怎,但是B里面有A的對(duì)象引用校焦。
4.B實(shí)例化完成后,繼續(xù)A完成實(shí)例化统倒。
5.整個(gè)A跟B全部實(shí)例化成功
4.為什么要用三級(jí)緩存
從剛才那個(gè)例子來看寨典,我們二級(jí)緩存完全沒有任何問題,那么spring為什么還要加一個(gè)三層7看摇耸成!
我們忽略了一個(gè)點(diǎn),就是我bean實(shí)例化后的對(duì)象后面可能會(huì)改變浴鸿,也就是我們的aop井氢,會(huì)變成我們的代理類!岳链!
大家看過源碼應(yīng)該都知道花竞,我們的aop是哪里實(shí)現(xiàn)的?
是在我們初始化的方法掸哑,不是實(shí)例化的方法约急,也不是DI的方法,而是在
initializeBean(beanName, exposedObject, mbd); //里面的after方法苗分,既然是代理增強(qiáng)厌蔽,肯定得類初始化完成,不然沒有任何意義
....
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
...
AbstractAutoProxyCreator.java.java的wrapIfNecessary()
所以俭嘁,如果是AOP,如果只是用二級(jí)緩存的話躺枕,我們會(huì)得到一個(gè)什么問題?
singletonFactories 中是我們的原型對(duì)象,而singletonObjects中是我們的代理對(duì)象9赵啤罢猪!
因?yàn)閟ingletonFactories是在我們代理之前加入的,而singletonObjects是在我對(duì)象初始化完后才進(jìn)入的2娲瘛I排痢!
這樣我緩存依賴的時(shí)候薇缅,B我拿到的是原型對(duì)象危彩,但是其實(shí)我應(yīng)該依賴的是代理對(duì)象!泳桦!所以汤徽,如果只有二級(jí)緩存依賴的話,會(huì)導(dǎo)致2個(gè)緩存的對(duì)象不一致
5.三級(jí)緩存為什么能解決灸撰?
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
我們發(fā)現(xiàn)三級(jí)緩存谒府,跟1.2級(jí)的緩存不一樣,存的不是Object浮毯,而是一個(gè)匿名內(nèi)部類完疫,調(diào)用getEarlyBeanReference方法
最終調(diào)用到AbstractAutoProxyCreator.java的wrapIfNecessary,就是我們動(dòng)態(tài)代理的方法