1. 程式人生 > >Spring源碼分析(十三)緩存中獲取單例bean

Spring源碼分析(十三)緩存中獲取單例bean

ould for 目的 存儲 不同 單例 color 正在 span

摘要:本文結合《Spring源碼深度解析》來分析Spring 5.0.6版本的源代碼。若有描述錯誤之處,歡迎指正。

介紹過FactoryBean的用法後,我們就可以了解bean加載的過程了。前面已經提到過,單 例在Spring的同一個容器內只會被創建一次,後續再獲取bean直接從單例緩存中獲取,當然這裏也只是嘗試加載,首先嘗試從緩存中加載,然後再嘗試從singletonFactories中加載。 因為在創建單例bean的時候會存在依賴註人的情況,而在創建依賴的時候為了避免循環依賴, Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加人到 緩存中,一旦下一個bean創建時需要依賴上個bean,則直接使用ObjectFactory。

@Override
@Nullable
public Object getSingleton(String beanName) {
    // 參數true設置標識允許早期依賴
    return getSingleton(beanName, true);
}

/**
 * Return the (raw) singleton object registered under the given name.
 * <p>Checks already instantiated singletons and also allows for an early
 * reference to a currently created singleton (resolving a circular reference).
 * 
@param beanName the name of the bean to look for * @param allowEarlyReference whether early references should be created or not * @return the registered singleton object, or {@code null} if none found */ @Nullable protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 檢査緩存中是否存在實例
Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { // 如果為空,則鎖定全局變量並進行處理 synchronized (this.singletonObjects) { // 如果此bean正在加載則不處理 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 當某些方法需要提前初始化的時候則會調用addSingletonFactory方法將對應的ObjectFactory初始化策路存儲在 singletonFactories ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 調用預先設定的getObject方法 singletonObject = singletonFactory.getObject(); // 記錄在緩存中,earlySingletonObjects和singletonFactories互斥 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return singletonObject; }

這個方法因為涉及循環依賴的檢測,以及涉及很多變量的記錄存取,所以讓很多讀者摸不著頭腦。這個方法首先嘗試從singletonObjects面獲取實例,如果獲取不到再從earlySingletonObjects裏面獲取,如果還獲取不到,再嘗試從singletonFactories裏面獲取beanName對應的ObjectFactory,然後調用這個ObjectFactory的getObject 來創建bean,並放到 earlySingletonObjects裏面去,並且從singletonFacotories裏面remove掉這個ObjectFactory,而對於後續的所有內存操作都只為了循環依賴檢測時候使用,也就是在allowEarlyReference為true的情況下才會使用。
這甩涉及用於存儲bean的不同的map,可能讓讀者感到崩潰,簡單解釋如下。

singletonObjects 用於保存 beanName 和創建 bean 實例之間的關系,bean name -> bean instance
singletonFactories 用於保存beanName 和創建bean的工廠之間的關系,bean name -> ObjectFactory
earlySingletonObjects 也是保存beanName 和創建bean實例之間的關系,與 singletonObjects的不同之處在於,當一個單例bean被放到這裏面後,那麽當bean還在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用
registeredSingletons 用來保存當前所有已註冊的bean

Spring源碼分析(十三)緩存中獲取單例bean