Spring源碼中getBean實例的詳細流程

本文主要研究getBean的流程。

1.首先嚐試框架會從容器的緩存裏獲取單例Bean實例,這個單例Bean有可能是一個普通Bean,也有可能是一個FactoryBean,然後調用他的getObject方法返回。
2.如果這裏1獲取不到,不管是單例還是原型模式,都要框架另外創建實例了。然後進行循環依賴的判斷邏輯,正是因爲循環依賴,纔會用到三級緩存,
3.如果該容器中沒有該Bean的BeanDefiniton實例,則遞歸去父容器去查找。
4.如果該容器中有該Bean的BeanDefiniton實例,則獲取Bean實例。
5.遞歸實例化顯式依賴的Bean。顯式依賴在其BeanDefiniton設置了Depends-On屬性。假設A Depends - On B,那麼B 就會先於A實例化。
6.根據不同的Scope選擇不同的策略創建Bean實例。
7.對Bean經行類型檢查。

下面直接看看代碼吧
在這裏插入圖片描述
這行代碼直接返回Bean的名字,這裏支持別名獲取,和加了&前綴獲取生產的Bean的工廠類本身。
然後嘗試從緩存中獲取Bean實例。

	// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
	//嘗試從一級緩存獲取Bean實例,singletonObjects就是單例Bean的一級緩存
		Object singletonObject = this.singletonObjects.get(beanName);
		//如果完整的Bean實例美與被創建出來再一級緩存,那麼就會將其加入到SingletonCurrentlyInCreation中 
		//如果一級緩存沒有,且這個Bean正在創建
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		//對一級緩存加鎖,防止幾個線程對緩存同時 操作,導致數據對不上。
			synchronized (this.singletonObjects) {
			//嘗試從二級緩存中獲取Bean實例,注意這裏的二級和後面的三級緩存不是ConcurrentMap,具體原因自己思考吧
				singletonObject = this.earlySingletonObjects.get(beanName);
				//如果二級緩存也沒有,且存在早期引用,說明是循環依賴。
				if (singletonObject == null && allowEarlyReference) {
				//從三級緩存獲取創建Bean實例的工廠
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					//如果哦從三級緩存獲取到的工廠 不爲空,則從工廠裏面獲取Bean實例
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						//放到二級緩存
						this.earlySingletonObjects.put(beanName, singletonObject);
						//從三級緩存刪除,保證緩存的一致性
						//注意:只有一級緩存保存的是完整的Bean.
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

到了這裏,邏輯上差不多結束了。然後Spring會根據FactoryBean前綴判斷到底需要獲取 的是工廠類還是.Bean本身。
在這裏插入圖片描述
以上邏輯是單例Bean的獲取,和從緩存中獲取到實例的情況。如果沒有呢,那麼就會繼續就會執行下面的邏輯。

// 可以看到原型模式也有一個註冊列表,如果此時還在註冊表中,說明是循環依賴,原型模式的循環依賴誤無解,直接拋出異常。而這裏的註冊表是ThreadLocal對象,也就是說在一個線程中出現了循環依賴,無解。
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

如果從當前容器中找不到這個Bean的BeanDefinition,且該容器存在父容器,則遞歸從父容器尋找。
找到BeanDefiniton,如果BeanDefiniton裏面具有顯示的循環依賴,拋出異常 。
在這裏插入圖片描述
然後根據不同的Scope的Bean創建。
創建完成後,在一級緩存中加入Bean實例,並且在二級三級刪除。在已註冊名單中加入這個Bean.正創建名單中清楚這個Bean

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章