Spring Ioc原始碼分析系列--Bean例項化過程(一)

Codegitz發表於2022-05-26

Spring Ioc原始碼分析系列--Bean例項化過程(一)

前言

上一篇文章Spring Ioc原始碼分析系列--Ioc容器註冊BeanPostProcessor後置處理器以及事件訊息處理已經完成了對IoC容器啟動方法也就是refresh()方法的簡單分析。但是之前的分析在對容器例項化Bean的過程的略過了,留到了這後續的文章分析,所以這篇文章會對Bean的例項化過程做一個介紹。

首先來理一下本文的思路:關鍵詞是例項化。由於Spring是利用反射實現的例項化,腦子裡先簡單想一下Java裡利用發射例項化一個物件需要哪些步驟和操作。毫無疑問,我們首先要知道物件的class,接著需要確定使用什麼建構函式以及確定建構函式的引數等。利用這些已經基本可以實現一個物件的例項化,當然實際上需要的東西可能更多更復雜,這裡只是舉個例子。那麼需要的這些資訊可以去哪裡提取呢?對Spring有了解的可能都馬上能想到BeanDefinition,這是一份原料表,裡面有我們構造一個例項化物件所需的所有引數。如果不太理解這個定義,可以參考一下上篇文章的例子。

如果不清楚BeanDefinition是從哪裡來的以及不清楚如何定義的,可以參考之前的文章Spring Ioc原始碼分析系列--Ioc原始碼入口分析的關鍵實現系列方法 loadBeanDefinitions ()。這篇文章講解註冊的時候只是說了註冊到容器裡,並沒有說明具體是註冊到了哪裡,這裡點明一下,所謂講BeanDefinition註冊到容器裡,就是將BeanDefinition放入到容器的一個Map裡,具體是註冊到了DefaultListableBeanFactorybeanDefinitionMap屬性裡,beanName會儲存到beanDefinitionNames屬性裡,這是個list集合,裡面的beanName會保持註冊時候的順序。

例項化的開始就是從遍歷所有的beanName開始,話不多說,開始分析吧。

原始碼分析

bean例項化入口

還記得例項化入口的方法名嗎?回憶一下,算了,反正也不會有人記得。是beanFactory.preInstantiateSingletons(),具體實現是在DefaultListableBeanFactory類裡。

跟進程式碼檢視,可以看到,這段程式碼分為兩部分,第一個for迴圈用於先例項化物件,第二個for迴圈完成一些例項化之後的回撥操作。我們先來看第一個for迴圈,首先是遍歷所有的beanNames獲取BeanDefinition,然後根據工廠bean非工廠bean進行相應處理,最後呼叫getBean(beanName)例項化物件。注意這裡例項化的是非抽象的、單例的並且是非懶載入的bean,這個前提非常重要。

	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		// 所有bd的名稱
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		// 遍歷所有bd,一個個進行建立
		for (String beanName : beanNames) {
			// 獲取到指定名稱對應的bd
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 對不是延遲載入的單例的Bean進行建立
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				// 判斷是否是一個FactoryBean
				if (isFactoryBean(beanName)) {
					// 如果是一個factoryBean的話,先建立這個factoryBean,建立factoryBean時,需要在beanName前面拼接一個&符號
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean<?> factory = (FactoryBean<?>) bean;
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
											((SmartFactoryBean<?>) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							// 判斷是否是一個SmartFactoryBean,並且不是懶載入的,就意味著,在建立了這個factoryBean之後要立馬呼叫它的getObject方法建立另外一個Bean
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean<?>) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					// 不是factoryBean的話,我們直接建立就行了
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		// 在建立了所有的Bean之後,遍歷為所有適用的 bean 觸發初始化後回撥,也就是這裡會對延遲初始化的bean進行載入...
		for (String beanName : beanNames) {
			// 這一步其實是從快取中獲取對應的建立的Bean,這裡獲取到的必定是單例的
			Object singletonInstance = getSingleton(beanName);
			// 判斷是否是一個SmartInitializingSingleton,
			// 最典型的就是我們之前分析過的EventListenerMethodProcessor,
			// 在這一步完成了對已經建立好的Bean的解析,會判斷其方法上是否有 @EventListener註解,
			// 會將這個註解標註的方法通過EventListenerFactory轉換成一個事件監聽器並新增到監聽器的集合中
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}

獲取BeanDefinition

首先跟進getMergedLocalBeanDefinition(beanName)方法,這裡首先會嘗試從mergedBeanDefinitions裡去獲取,這個mergedBeanDefinitions存放著已經合併過的BeanDefinition,獲取不到再真正呼叫getMergedBeanDefinition(beanName, getBeanDefinition(beanName))去獲取。

	/**
	 * Return a merged RootBeanDefinition, traversing the parent bean definition
	 * if the specified bean corresponds to a child bean definition.
	 *
	 * 返回一個合併的 RootBeanDefinition,如果指定的 bean 對應於子 bean 定義,則遍歷父 bean 定義。
	 *
	 * @param beanName the name of the bean to retrieve the merged definition for
	 * @return a (potentially merged) RootBeanDefinition for the given bean
	 * @throws NoSuchBeanDefinitionException if there is no bean with the given name
	 * @throws BeanDefinitionStoreException in case of an invalid bean definition
	 */
	protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
		// Quick check on the concurrent map first, with minimal locking.
		// 首先檢查 mergedBeanDefinitions ,最小程度影響併發效能
		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
		if (mbd != null && !mbd.stale) {
			return mbd;
		}
		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
	}

先看getBeanDefinition(beanName),這個方法就是簡單的去beanDefinitionMap裡獲取BeanDefinition,如果獲取不到,就丟擲異常。beanDefinitionMap就是上面說到的BeanDefinition存放的地方。

	public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
		if (bd == null) {
			if (logger.isTraceEnabled()) {
				logger.trace("No bean named '" + beanName + "' found in " + this);
			}
			throw new NoSuchBeanDefinitionException(beanName);
		}
		return bd;
	}

接下來就進入到getMergedBeanDefinition()方法獲取BeanDefinition,為啥要從beanDefinitionMap獲取了還進行一個merged獲取呢?這是因為Bean有層次關係,子類需要合併父類的屬性方法等,所以要進行一次合併,合併完成後會放入到mergedBeanDefinitions裡,功能和屬性名區分度還是十分貼切的?。

跟進方法,程式碼已新增註釋,比較簡單,跟著看看就行。

	/**
	 * Return a RootBeanDefinition for the given top-level bean, by merging with
	 * the parent if the given bean's definition is a child bean definition.
	 *
	 * 如果給定 bean 的定義是子 bean 定義,則通過與父級合併返回給定頂級 bean 的 RootBeanDefinition。
	 *
	 * @param beanName the name of the bean definition
	 * @param bd the original bean definition (Root/ChildBeanDefinition)
	 * @return a (potentially merged) RootBeanDefinition for the given bean
	 * @throws BeanDefinitionStoreException in case of an invalid bean definition
	 */
	protected RootBeanDefinition getMergedBeanDefinition(String beanName, BeanDefinition bd)
			throws BeanDefinitionStoreException {

		return getMergedBeanDefinition(beanName, bd, null);
	}

	/**
	 * Return a RootBeanDefinition for the given bean, by merging with the
	 * parent if the given bean's definition is a child bean definition.
	 *
	 * 如果給定 bean 的定義是子 bean 定義,則通過與父合併返回給定 bean 的 RootBeanDefinition
	 *
	 * @param beanName the name of the bean definition
	 * @param bd the original bean definition (Root/ChildBeanDefinition)
	 * @param containingBd the containing bean definition in case of inner bean,
	 * or {@code null} in case of a top-level bean
	 *    如果是內部 bean,則包含 bean 定義,如果是頂級 bean,則為 {@code null}
	 * @return a (potentially merged) RootBeanDefinition for the given bean
	 * @throws BeanDefinitionStoreException in case of an invalid bean definition
	 */
	protected RootBeanDefinition getMergedBeanDefinition(
			String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
			throws BeanDefinitionStoreException {

		synchronized (this.mergedBeanDefinitions) {
			RootBeanDefinition mbd = null;
			RootBeanDefinition previous = null;

			// Check with full lock now in order to enforce the same merged instance.
			// 現在檢查完全鎖定以強制執行相同的合併例項。
			if (containingBd == null) {
				mbd = this.mergedBeanDefinitions.get(beanName);
			}

			if (mbd == null || mbd.stale) {
				previous = mbd;
				mbd = null;
				if (bd.getParentName() == null) {
					// Use copy of given root bean definition.
					// 使用給定根 bean 定義的副本。
					if (bd instanceof RootBeanDefinition) {
						mbd = ((RootBeanDefinition) bd).cloneBeanDefinition();
					}
					else {
						mbd = new RootBeanDefinition(bd);
					}
				}
				else {
					// Child bean definition: needs to be merged with parent.
					// 子bean定義:需要與父合併。
					BeanDefinition pbd;
					try {
						String parentBeanName = transformedBeanName(bd.getParentName());
						if (!beanName.equals(parentBeanName)) {
							pbd = getMergedBeanDefinition(parentBeanName);
						}
						else {
							BeanFactory parent = getParentBeanFactory();
							if (parent instanceof ConfigurableBeanFactory) {
								pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName);
							}
							else {
								throw new NoSuchBeanDefinitionException(parentBeanName,
										"Parent name '" + parentBeanName + "' is equal to bean name '" + beanName +
										"': cannot be resolved without an AbstractBeanFactory parent");
							}
						}
					}
					catch (NoSuchBeanDefinitionException ex) {
						throw new BeanDefinitionStoreException(bd.getResourceDescription(), beanName,
								"Could not resolve parent bean definition '" + bd.getParentName() + "'", ex);
					}
					// Deep copy with overridden values.
					// 具有覆蓋值的深拷貝。
					mbd = new RootBeanDefinition(pbd);
					mbd.overrideFrom(bd);
				}

				// Set default singleton scope, if not configured before.
				// 如果之前未配置,則設定預設單例範圍。
				if (!StringUtils.hasLength(mbd.getScope())) {
					mbd.setScope(RootBeanDefinition.SCOPE_SINGLETON);
				}

				// A bean contained in a non-singleton bean cannot be a singleton itself.
				// Let's correct this on the fly here, since this might be the result of
				// parent-child merging for the outer bean, in which case the original inner bean
				// definition will not have inherited the merged outer bean's singleton status.
				// 包含在非單例 bean 中的 bean 本身不能是單例。
				// 讓我們在這裡即時糾正這個問題,因為這可能是外部 bean 的父子合併的結果,
				// 在這種情況下,原始內部 bean 定義將不會繼承合併的外部 bean 的單例狀態。
				if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) {
					mbd.setScope(containingBd.getScope());
				}

				// Cache the merged bean definition for the time being
				// (it might still get re-merged later on in order to pick up metadata changes)
				// 暫時快取合併的 bean 定義(它可能稍後仍會重新合併以獲取後設資料更改)
				if (containingBd == null && isCacheBeanMetadata()) {
					this.mergedBeanDefinitions.put(beanName, mbd);
				}
			}
			if (previous != null) {
				copyRelevantMergedBeanDefinitionCaches(previous, mbd);
			}
			return mbd;
		}

建立Bean

獲取BeanDefinition完成後,接下來就呼叫getBean(beanName)進行bean的例項化了。當然這裡的建立還是分了工廠Bean和非工廠Bean兩個邏輯,如果是一個工廠Bean,那麼getBean(beanName)這一步只會建立一個工廠Bean,接下來會通過isEagerInit引數判斷是否需要初始化工廠Bean的物件,如果需要,再呼叫getBean(beanName)去立馬獲取工廠Bean需要生產的物件。不是工廠Bean的話,直接一步到位建立物件了,少一分曲折。

跟進程式碼檢視,可以看到真正的執行程式碼的是在doGetBean()方法裡。跟進doGetBean()方法,發現程式碼非常的長,這裡我會把這個方法切分成幾塊去解析。

	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

由於程式碼量比較大,這裡貼一張圖,展示各個部分間的作用,然後對每個部分進行逐步分析。

1653547332139

看起來是不是很簡單,其實每一部分都包含了大量的細節操作,先來看第一步的名稱轉換,這個比較簡單。

名稱轉換

這一步就是把&開頭的name轉換成不帶&name

	/**
	 * Return the bean name, stripping out the factory dereference prefix if necessary,
	 * and resolving aliases to canonical names.
	 *
	 * 返回 bean 名稱,必要時去除工廠取消引用字首,並將別名解析為規範名稱。
	 *
	 * @param name the user-specified name
	 * @return the transformed bean name
	 */
	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

可以看到這裡會有個迴圈去處理,帶有多個&的都會被去掉。

	/**
	 * Return the actual bean name, stripping out the factory dereference
	 * prefix (if any, also stripping repeated factory prefixes if found).
	 *
	 * 返回實際的 bean 名稱,去除工廠取消引用字首(如果有,也去除重複的工廠字首,如果找到)。
	 *
	 * @param name the name of the bean
	 * @return the transformed name
	 * @see BeanFactory#FACTORY_BEAN_PREFIX
	 */
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}

確定名稱,一個Bean可能會有很多委派的別名,這個時候需要確定最根本的那個name,用這個最根本的name來作為beanName去進行後續的操作,這裡同樣有個迴圈去處理,因為別名也會有多重,會存在別名的別名這種情況。

	/**
	 * Determine the raw name, resolving aliases to canonical names.
	 * 確定原始名稱,將別名解析為規範名稱。
	 * @param name the user-specified name
	 * @return the transformed name
	 */
	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		// 處理別名...
		String resolvedName;
		do {
			// 可能會有別名層層巢狀的情況,所以需要獲取到最終的名稱
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

從容器快取中獲取Bean

在上一步中我們已經獲取到了真正的beanName,那麼接下來,就可以利用這個beanName到容器的快取中嘗試獲取bean,如果之前已經建立過,這裡就可以直接獲取到bean。這裡的快取包括三級,但是這三級快取並不是包含的關係,而是一種互斥的關係,一個bean無論處於何種狀態,它在同一時刻只能處於某個快取當中。

跟進getSingleton(beanName)方法程式碼。

	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}

可以看到這裡預設給多了一個引數為true,這引數為allowEarlyReference,用來控制是否允許迴圈依賴。方法程式碼註釋比較詳細,就是逐個快取去獲取,跟著看一下問題不大。第一次進來肯定是獲取不到任何東西的,所以這裡會返回null

	/**
	 * 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).
	 *
	 * 返回在給定名稱下注冊的(原始)單例物件。
	 * <p>檢查已經例項化的單例,並允許提前引用當前建立的單例(解決迴圈引用)。
	 *
	 * @param beanName the name of the bean to look for 要查詢的 bean 的名稱
	 * @param allowEarlyReference whether early references should be created or not 是否應建立早期引用
	 * @return the registered singleton object, or {@code null} if none found 註冊的單例物件,如果沒有找到則為 {@code null}
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 檢測一級快取中是否存在例項
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			// 如果為空,則鎖定全域性變數進行處理
			synchronized (this.singletonObjects) {
				// 從二級快取 earlySingletonObjects 中獲取
				singletonObject = this.earlySingletonObjects.get(beanName);
				// 二級快取中沒有,並且 allowEarlyReference = true 允許提前建立早期引用,則到三級快取中獲取
				// 早期引用一般是用來指向需要經過代理的bean或者是需要延遲初始化的bean
				if (singletonObject == null && allowEarlyReference) {
					// 當某些方法需要提前初始化的時候,則會呼叫addSingletonFactory方法
					// 將對應的objectFactory初始化策略儲存在singletonFactories
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						// 這裡的實現是一個lambada表示式,具體的實現有很多種
						// 呼叫預先設定的getObject方法,也就是呼叫之前加入的 getEarlyBeanReference()方法
						// 此表示式是在 doCreateBean() 方法中呼叫 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)) 加入的
						singletonObject = singletonFactory.getObject();
						// 將bean加入二級快取中
						this.earlySingletonObjects.put(beanName, singletonObject);
						// 同時從三級快取中將bean移除,也就是移除一個ObjectFactory,對應為一個lambada表示式
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

快取存在bean

這裡講解的是截圖的第三部分,程式碼是第260行到276行左右。

		if (sharedInstance != null && args == null) {
			// 省略部分日誌...
			// 如果直接從單例池中獲取到了這個 bean(sharedInstance),我們能直接返回嗎?
			// 當然不能,因為獲取到的 Bean 可能是一個 factoryBean,
			// 如果我們傳入的 name 是 & + beanName 這種形式的話,
			// 那是可以返回的,但是我們傳入的更可能是一個 beanName,
			// 那麼這個時候 Spring 就還需要呼叫這個 sharedInstance 的 getObject 方法來建立真正被需要的 Bean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

可以看到,去除日誌後,只剩下一個主要的方法,跟進getObjectForBeanInstance()程式碼檢視。可以看到這裡會進行一些型別的判斷,會嘗試從快取獲取,最後會呼叫getObjectFromFactoryBean方法從FactoryBean裡獲取例項物件。

	/**
	 * Get the object for the given bean instance, either the bean
	 * instance itself or its created object in case of a FactoryBean.
	 *
	 * 獲取給定 bean 例項的物件,bean 例項本身或其建立的物件(如果是 FactoryBean)。
	 *
	 * @param beanInstance the shared bean instance
	 * @param name name that may include factory dereference prefix
	 * @param beanName the canonical bean name
	 * @param mbd the merged bean definition
	 * @return the object to expose for the bean
	 */
	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		// 如果指定的name是工廠相關(以&為字首)且 beanInstance又不是FactoryBean型別則驗證不通過
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
			if (mbd != null) {
				mbd.isFactoryBean = true;
			}
			return beanInstance;
		}

		// Now we have the bean instance, which may be a normal bean or a FactoryBean.
		// If it's a FactoryBean, we use it to create a bean instance, unless the
		// caller actually wants a reference to the factory.

		// 現在我們有了 bean 例項,它可能是普通的 bean 或 FactoryBean。
		// 如果它是一個 FactoryBean,我們使用它來建立一個 bean 例項,除非呼叫者實際上想要一個對工廠的引用。
		// 如果是普通bean,直接返回了
		if (!(beanInstance instanceof FactoryBean)) {
			return beanInstance;
		}

		//載入factoryBean
		Object object = null;
		if (mbd != null) {
			mbd.isFactoryBean = true;
		}
		else {
			//嘗試從快取中獲取
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			// Return bean instance from factory.
			// 到這裡可以確定 beanInstance 一定是 FactoryBean 型別
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// Caches object obtained from FactoryBean if it is a singleton.
			// 如果是單例,則快取從 FactoryBean 獲得的物件。
			// containsBeanDefinition 檢測 beanDefinitionMap 中也就是在所有已經載入的類中檢測是否定義 beanName
			if (mbd == null && containsBeanDefinition(beanName)) {
				// 將儲存XML檔案的 GenericBeanDefinition 轉換為 RootBeanDefinition,如果指定的 beanName 是子 bean 的話
				// 會同時合併父類的相關屬性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//是否是用使用者自己定義的還是用程式本身定義的
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

跟進getObjectFromFactoryBean()方法,該方法首先也是從快取獲取,然後呼叫doGetObjectFromFactoryBean()真正獲取bean物件,這裡會區分單例和原型分別去獲取,單例獲取完成後會放入快取,原型則每次都新建,所以原型bean的建立前前後後會省略很多步驟。獲取完成後根據shouldPostProcess判斷是否需要後置處理,從而執行BeanPostProcessor#postProcessAfterInitialization()後置處理器的方法,最後將物件放入快取中。這些處理思路跟我們平時寫業務程式碼的思路也是非常類似的,可以互相借鑑一下。

	/**
	 * Obtain an object to expose from the given FactoryBean.
	 *
	 * 從給定的 FactoryBean 中獲取要公開的物件。
	 *
	 * @param factory the FactoryBean instance
	 * @param beanName the name of the bean
	 * @param shouldPostProcess whether the bean is subject to post-processing bean是否經過後處理
	 * @return the object obtained from the FactoryBean
	 * @throws BeanCreationException if FactoryBean object creation failed
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		//如果是單例的話
		if (factory.isSingleton() && containsSingleton(beanName)) {
			//加鎖,保證單例
			synchronized (getSingletonMutex()) {
				//先從快取中獲取
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					//從FactoryBean中獲取bean
					object = doGetObjectFromFactoryBean(factory, beanName);
					// Only post-process and store if not put there already during getObject() call above
					// (e.g. because of circular reference processing triggered by custom getBean calls)
					// 如果在上面的 getObject() 呼叫期間尚未放置,則僅進行後處理和儲存(例如,由於自定義 getBean 呼叫觸發的迴圈引用處理)
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								// 暫時返回非後處理物件,暫不儲存..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								//呼叫ObjectFactory的後置處理器
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		else {
			// 從 FactoryBean 獲取物件
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					// 後置處理從 FactoryBean 獲取的物件
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

跟進doGetObjectFromFactoryBean()方法,這個方法就更簡單了,就是呼叫工廠bean的getObject()方法返回bean。

	/**
	 * Obtain an object to expose from the given FactoryBean.
	 *
	 * 從給定的 FactoryBean 中獲取要公開的物件。
	 *
	 * @param factory the FactoryBean instance
	 * @param beanName the name of the bean
	 * @return the object obtained from the FactoryBean
	 * @throws BeanCreationException if FactoryBean object creation failed
	 * @see org.springframework.beans.factory.FactoryBean#getObject()
	 */
	private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			//需要許可權校驗
			if (System.getSecurityManager() != null) {
				// 省略部分程式碼...
			}
			else {
				//直接呼叫factory.getObject()方法
				object = factory.getObject();
			}
		}
		catch (Throwable ex) {
			// 省略部分異常處理...
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		// 不要為尚未完全初始化的 FactoryBean 接受 null 值:許多 FactoryBean 只返回 null。
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}

到這裡,圖片上的第三部分過完了。接下來是第四步。

真正進入建立Bean的流程

經過前面這麼多鋪墊,才真正走到了建立Bean的地方。這裡會比較複雜且囉嗦,需要點耐心看完。

這部分程式碼如下,可以跟著註釋看下這段程式碼。這裡先對原型型別的迴圈依賴進行校驗,原型bean出現迴圈依賴直接拋異常。然後回去父容器裡獲取,緊接著又處理了被@DependsOn註解標註的依賴,然後再進行bean的建立。

			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 在快取中獲取不到這個Bean
			// 原型下的迴圈依賴直接報錯
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
			// 核心要義,找不到我們就從父容器中再找一次
			// 我們簡單的示例是不會有父容器存在的,這一塊可以理解為遞迴到父容器中查詢,跟在當前容器查詢邏輯是類似的
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				// 從父容器獲取,根據不同的引數呼叫不同的方法
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			// 如果不僅僅是為了型別推斷,也就是代表我們要對進行例項化
			// 那麼就將bean標記為正在建立中,其實就是將這個beanName放入到alreadyCreated這個set集合中
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				// 為什麼這裡需要再獲取一次,因為經過之前的操作,RootBeanDefinition 可能已經發生了改變,
				// 其中的 stale 屬性可能已經設為 true,這時需要去容器裡重新獲取,而不是直接從快取中返回
				// 例如上面的 markBeanAsCreated() 方法就會修改 stale 屬性
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 檢查合併後的bd是否是abstract,這個檢查現在已經沒有作用了,必定會通過
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				// @DependsOn註解標註的當前這個Bean所依賴的bean名稱的集合,
				// 就是說在建立當前這個Bean前,必須要先將其依賴的Bean先完成建立
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					// 遍歷所有申明的依賴
					for (String dep : dependsOn) {
						// 如果這個bean所依賴的bean又依賴了當前這個bean,出現了迴圈依賴,直接報錯
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						// 註冊bean跟其依賴的依賴關係,key為依賴,value為依賴所從屬的bean
						registerDependentBean(dep, beanName);
						try {
							// 先建立其依賴的Bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.建立bean例項
				// 我們目前只分析單例的建立,單例看懂了,原型自然就懂了
				if (mbd.isSingleton()) {
					// 這裡再次呼叫了 getSingleton() 方法,
					// 這裡跟方法開頭呼叫的 getSingleton() 的區別在於,
					// 這個方法多傳入了一個 ObjectFactory 型別的引數,
					// 這個 ObjectFactory 會返回一個 Bean
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							// 從單例快取中顯式刪除例項:它可能已被建立過程提前地放在那裡,以允許迴圈引用解析。
							// 還要刪除任何接收到對 bean 的臨時引用的 bean。
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						// 省略部分異常處理...
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}

其實去掉部分校驗,去掉部分複雜場景下才會有的邏輯,核心程式碼就是getSingleton(String beanName, ObjectFactory<?> singletonFactory) 方法,這個方法是不是有點眼熟,getSingleton()有三個同名的過載方法。前兩個上面已經見過,這裡是第三個。

1653556824388

仔細看這段程式碼,singletonFactory部分傳入的是個lambada表示式,裡面是正常建立bean的createBean()方法。

sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// 省略部分異常處理...
						}
					});

結合getSingleton()方法檢視,該方法處理一些前置判斷和後置處理後,核心的程式碼就是singletonFactory.getObject()方法,這裡執行的就是上面傳入的lambada表示式,也就是會執行到createBean(beanName, mbd, args)方法。createBean(beanName, mbd, args)又是一個很曲折的方法,簡直是曲折他媽給曲折開門,曲折到家了。所以我打算下一篇Spring Ioc原始碼分析系列--Bean例項化過程(二)說。在建立完成後,會把bean放入單例快取singletonObjects中。

	/**
	 * Return the (raw) singleton object registered under the given name,
	 * creating and registering a new one if none registered yet.
	 *
	 * 返回以給定名稱註冊的(原始)單例物件,如果尚未註冊,則建立並註冊一個新物件。
	 *
	 * @param beanName the name of the bean
	 * @param singletonFactory the ObjectFactory to lazily create the singleton
	 * with, if necessary
	 * @return the registered singleton object
	 */
	public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
		Assert.notNull(beanName, "Bean name must not be null");
		synchronized (this.singletonObjects) {
			// 從單例池中獲取,第一次進來這個地方肯定獲取不到
			Object singletonObject = this.singletonObjects.get(beanName);
			if (singletonObject == null) {
				// 工廠已經在銷燬階段了,這個時候還在建立Bean的話,就直接丟擲異常
				if (this.singletonsCurrentlyInDestruction) {
					// 省略部分日誌及異常處理...
				}
				// 在單例建立前,記錄一下正在建立的單例的名稱,
				// 就是把beanName放入到singletonsCurrentlyInCreation這個set集合中去
				beforeSingletonCreation(beanName);
				boolean newSingleton = false;
				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
				if (recordSuppressedExceptions) {
					this.suppressedExceptions = new LinkedHashSet<>();
				}
				try {
					// 這裡呼叫了singletonFactory的getObject方法,
					// 對應的實現就是在doGetBean中的那一段lambda表示式
					singletonObject = singletonFactory.getObject();
					newSingleton = true;
				}
				catch (IllegalStateException ex) {
					// Has the singleton object implicitly appeared in the meantime ->
					// if yes, proceed with it since the exception indicates that state.
					// 單例物件是否同時隱式出現 -> 如果是,則繼續執行,因為異常指示該狀態。
					singletonObject = this.singletonObjects.get(beanName);
					if (singletonObject == null) {
						throw ex;
					}
				}
				catch (BeanCreationException ex) {
					// 省略部分異常處理...
				}
				finally {
					if (recordSuppressedExceptions) {
						this.suppressedExceptions = null;
					}
					// 在單例完成建立後,將beanName從singletonsCurrentlyInCreation中移除
					// 標誌著這個單例已經完成了建立
					afterSingletonCreation(beanName);
				}
				if (newSingleton) {
					// 新增到單例池中
					addSingleton(beanName, singletonObject);
				}
			}
			return singletonObject;
		}
	}

進行型別轉換

這裡已經分析到了截圖的第五部分,由於第四部分真正建立bean的部分放到了下一篇Spring Ioc原始碼分析系列--Bean例項化過程(二)去分析,所以到這裡的時候,我們已經完成了bean的建立,這個時候,如果方法傳入的requiredType不為空,那麼就需要進行型別轉換,如果轉換失敗,則丟擲異常。轉換成功則返回當前完成型別轉換的convertedBean。至此,建立bean的流程結束,已經可以返回一個可使用的bean,是不是還是挺簡單的。流程清晰。關於Spring的型別轉換和校驗也可以分一篇文章去分析TypeConverterConversionService在Spring體系裡的前世今生,這裡就不再贅述了。

		// Check if required type matches the type of the actual bean instance.
		// 檢查所需型別是否與實際 bean 例項的型別匹配。
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}

回撥SmartInitializingSingleton實現類

到這裡完成單例bean的建立了,那就到了最後一步了,回撥SmartInitializingSingleton#afterSingletonsInstantiated()方法,這裡沒啥好說的,就是第二個迴圈乾的事。遍歷所有的beanNames,然後完成回撥。

這裡的回撥有很多實現類,比較經典的是EventListenerMethodProcessor類,該類會在這一步完成了對已經建立好的Bean的解析,會判斷其方法上是否有 @EventListener註解,會將這個註解標註的方法通過EventListenerFactory轉換成一個事件監聽器並新增到監聽器的集合中。

總結

這篇文章還是按照之前的行文思路,分析得比較扁平,每個方法都沒有特別過分的深入去講解,因為那樣太深了很多人受不了,容易翻車。

回顧一下本文的思路,先是順著上文的入口,開始分析bean的建立。首先是獲取BeanDefinition,然後是呼叫getBean(beanName)方法進行物件的例項化。該方法由一個截圖,分為了五部分去解析。分為了哪五部分還記得嗎?忘記了?那不怪你,我瞎幾把寫的。

第四步建立bean的部分我留到了下一篇去分析,這樣思路應該也比較清晰,不會那麼容易翻車。

如果有人看到這裡,那在這裡老話重提。與君共勉,路漫漫其修遠兮,吾將上下而求索。

相關文章