天天看點

八、Spring 源碼解析之 bean 的加載流程三: bean 的執行個體化

  在六、Spring 源碼解析之 bean 的加載過程介紹中我們介紹了bean 的加載的大緻流程,其中第一步已經在該文中說過,這裡來說第三步:bean 的執行個體化。

  在 getBean() 方法中,getObjectForBeanInstance() 是個高頻率使用的方法,無論是從緩存中擷取 bean 還是根據不同的 scope 政策加載 bean。總之,我們得到 bean 的執行個體後要做的第一步就是調用這個方法來檢測一下正确性,其實就是用于檢測目前 bean 是否是 FactoryBean 類型的 bean ,如果是,那麼需要調用該 bean 對應的 FactoryBean 執行個體中的 getObject() 作為傳回值。

  無論是從緩存中擷取到的 bean 還是通過不同的 scope 政策加載的 bean 都隻是最原始的 bean 狀态,并不一定是我們最終想要的 bean。舉個栗子,假如我們需要對工廠 bean 進行處理,那麼這裡得到的其實是工廠 bean 的初始狀态,但是我們真正需要的是工廠 bean 中定義的

factory-methods

方法傳回的 bean,而

getObjectForBeanInstance()

方法就是完成這個工作的。

  • AbstractBeanFactory#doGetBean(final String name, @Nullable final Class requiredType,@Nullable final Object[] args, boolean typeCheckOnly)

    • AbstractBeanFactory#getObjectForBeanInstance(Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd)

      • FactoryBeanRegistrySupport#getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess)

        • FactoryBeanRegistrySupport#doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)

        • AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean(Object object, String beanName)

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 是工廠相關(以 & 為字首)
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			//如果指定的 name 是工廠相關(以 & 為字首)但是 beanInstance 又不是 FactoryBean 類型則驗證不通過
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}

		// 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.
		/*
		 * 現在我們有了 beanInstance 這個執行個體,這個執行個體有可能是正常的 bean 或者是 FactoryBean:
		 *   若不是 FactoryBean ,那麼就是正常的 bean 執行個體,直接傳回即可
		 *   若是 FactoryBean,且傳入的 name 加上了 & 字首,那麼說明用戶端想擷取工廠執行個體而不是工廠的 getObject() 方法傳回
		 * 的執行個體,直接傳回即可
		 */
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		/*
		 *     加載 FactoryBean(條件:若是 FactoryBean 且傳入的 name 沒有加上 & 字首,說明希望調用 Factory#getObject()
		 * 傳回 bean 執行個體)
		 */
		Object object = null;
		if (mbd == null) {
			//嘗試從緩存中加載 bean
			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.
			//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;
	}
           

  上面代碼來看,真正核心代碼委托給了

FactoryBeanRegistrySupport#getObjectFromFactoryBean()

方法。

getObjectForBeanInstance()

方法主要做了如下工作:

1.對 FactoryBean 正确性的驗證。

2.對非 FactoryBean 不做任何處理。

3.對 bean 進行轉換

4.将從 Factory 中解析 bean 的工作委托給

FactoryBeanRegistrySupport#getObjectFromFactoryBean()

/**
	 * 方法功能:
	 *     傳回的 bean 若是單例的,那就必須要保證全局唯一性,同時,也因為是單例的,是以不必重複建立,可以使用緩存來提高
	 * 性能,也就是說已經加載過就要記錄下來以便于下次複用,否則的話就直接擷取
	 */
	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) {
					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)
					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 {
								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 {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}
           

  在這個方法裡隻做了一件事,就是傳回的 bean 若是單例的,那就必須要保證全局唯一性,同時,也因為是單例的,是以不必重複建立,可以使用緩存來提高性能,也就是說已經加載過就要記錄下來以便于下次複用,否則的話就直接擷取。

  在

FactoryBeanRegistrySupport#doGetObjectFromFactoryBean()

方法中我們最終看到了我們想要尋找的方法

factory.getObject()

,代碼如下:

private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			//需要權限驗證
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					// factory::getObject:函數式程式設計,其實就是調用 getObject() 方法
					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				// 直接調用 getObject() 方法
				object = factory.getObject();
			}
		}
		catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		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;
	}
           

  上面我們已經講述了

FactoryBean

的調用方法,若 bean 聲明為

FactoryBean

類型,則當提取 bean 時提取的并不是

FactoryBean

,而是

FactoryBean

中對應的

getObject()

方法傳回的 bean,而

doGetObjectFromFactoryBean()

正是實作這個功能的。但是在

FactoryBeanRegistrySupport#getObjectFromFactoryBean()

方法中

FactoryBeanRegistrySupport#doGetObjectFromFactoryBean()

得到 bean 以後并沒有直接傳回,而是接下來又做了些後處理操作,這個是做什麼的?我們跟蹤

FactoryBeanRegistrySupport#postProcessObjectFromFactoryBean()

方法進入:

protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
		return object;
	}
           

  發現是直接傳回 bean,啥操作沒有,其實是因為真正并不是調用這個方法,而是被子類

AbstractAutowireCapableBeanFactory

重寫了該方法。其中繼承關系如:

FactoryBeanRegistrySupport

-->

AbstractBeanFactory

-->

AbstractAutowireCapableBeanFactory

。我們來看一下重寫後的方法:

AbstractAutowireCapableBeanFactory#postProcessObjectFromFactoryBean()

@Override
	protected Object postProcessObjectFromFactoryBean(Object object, String beanName) {
		return applyBeanPostProcessorsAfterInitialization(object, beanName);
	}
	
	@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}
           

  對于後處理器的使用我們還未過多接觸,後續章節會使用大量篇幅介紹,這裡,我們隻需了解在 Spring 擷取 bean 的規則中有這樣一條:盡可能保證所有 bean 初始化後都會調用注冊的 BeanPostProcessor 的 postProcessAfterInitialization() 方法進行處理,在實際開發過程中大可以針對此特性設計自己的業務邏輯。