上一篇博客,講了下spring如何初始化bean的 當然,當時只討論了很簡單的一種情況:初次加載bean時候,并且只考慮了單例。
這篇博客會試著理清楚spring在加載bean的時候的一部分緩存。關于解決循環引用所使用的緩存,可以看這篇博客
從doGetBean開始
首先再次回到doGetBean方法
上一篇博客里,我對doGetBean進行了簡化,省略了很多多例及第二次加載相關的代碼。
現在想下,如果讓我們業務上使用緩存會怎么做。
1)先從緩存查下有沒有所需數據
2)沒有的話從db加載
3)加載后存到緩存里
緩存的用法無非是這樣。spring也是這樣使用的。
getSingleton方法
現在再來回顧getSingleton方法就很清楚了
這里我會把流程再簡化下,去掉那些擴展的,異常處理等
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {Assert.notNull(beanName, "'beanName' must not be null");synchronized (this.singletonObjects) {//先試著從緩存中加載Object singletonObject = this.singletonObjects.get(beanName);if (singletonObject == null) {//異常檢查 ... //...beforeSingletonCreation(beanName);boolean newSingleton = false;//異常記錄...try {//調用ObjectFactory的getObject生成這個對象singletonObject = singletonFactory.getObject();newSingleton = true;}// 省略了異常處理finally{//....afterSingletonCreation(beanName);}if (newSingleton) {//添加到緩存里addSingleton(beanName, singletonObject);}}return (singletonObject != NULL_OBJECT ? singletonObject : null);}
}
這樣看就非常清楚了
1)從singleObjects試著找下對應的對象
2)從singletonFactory里創建對象
3)添加到緩存中
和我們平常使用緩存的方式沒有任何不同
addSingleton記錄緩存
看doGetBean方法,讓我感到很暈的地方就是,各種各樣緩存。(好多hashMap)而addSingleton方法就是操作緩存的一部分入口。
protected void addSingleton(String beanName, Object singletonObject) {synchronized (this.singletonObjects) {this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));this.singletonFactories.remove(beanName);this.earlySingletonObjects.remove(beanName);this.registeredSingletons.add(beanName);}
}
這里我們先挑看得懂的來分析。
Map<String, Object> singletonObjects 存放了 beanName -> 創建出來的對象
Set<String> registeredSingletons 存放了已注冊的單例對象
好像就這兩個看得懂哦(~ ̄▽ ̄)~ 沒事我們繼續分析下去
回到doGetBean開頭
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {final String beanName = transformedBeanName(name);Object bean;Object sharedInstance = getSingleton(beanName);//.....
}
doGetBean一開始就試圖通過getSingleton方法獲取對應的bean
我們再回頭看下getSinglteton方法
protected Object getSingleton(String beanName, boolean allowEarlyReference) {//已創建的對象里面找下Object singletonObject = this.singletonObjects.get(beanName);//沒找到,并且當前類正在被創建if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {singletonObject = this.earlySingletonObjects.get(beanName);if (singletonObject == null && allowEarlyReference) {ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {singletonObject = singletonFactory.getObject();this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return (singletonObject != NULL_OBJECT ? singletonObject : null);
}
第一行很熟悉,從已加載的對象的緩存里找下。
第二行判斷,從方法名很容易猜到意思。只有當從緩存里找不到,并且當前類正在被創建才會走到里面的邏輯。
看下isSingletonCurrentlyInCreation方法
public boolean isSingletonCurrentlyInCreation(String beanName) {return this.singletonsCurrentlyInCreation.contains(beanName);
}
這里又出現了一個不認識的緩存 = =
Set<String> singletonsCurrentlyInCreation
從變量名,很容易猜到是記錄當前單例是否正在被創建。
我們跟下往這個set里添加 值的地方。插入值的地方就在getSingleton里的beforeSingletonCreation 這一步里。
之前分析getSingleton方法時,我關注的是如何創建bean,如何使用singletonObjects緩存的。
其實在創建bean前,與創建bean后,有兩個方法用于做些前置以及后置處理。分別是beforeSingletonCreation
與 afterSingletonCreation
方法。
我們看下這兩個方法里都做了啥
創建bean的前置與后置處理
protected void beforeSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}
}protected void afterSingletonCreation(String beanName) {if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");}
}
這里又出現了兩個緩存 inCreationCheckExclusions
和 singletonsCurrentlyInCreation
inCreationCheckExclusions這個我們先不管,到了這里singletonsCurrentlyInCreation就很清楚了,spring會在創建一個單例對象之前,記錄到singletonsCurrentlyInCreation里,在創建完后,從singletonsCurrentlyInCreation里刪除。
Set<String> singletonsCurrentlyInCreation 當前正在創建的beanName
回到getSingleton方法
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
到了這里我有幾個問題:
1)為啥getSingleton方法里要進行這樣的判斷?
2)一般來說我們使用spring時候,都是單線程的。那么按照這個代碼,創建之前添加進去,添加之后刪除。那么豈不是永遠不會走到這個if條件里?這些問題先記著,等分析依賴注入時候再回過頭來解決。
總結
到了這里,還是有很多不知道有什么用的緩存。這些緩存會在研究依賴注入以及循環引用時候繼續分析。