Spring官網閱讀(十)Spring中Bean的生命週期(下)

在上篇文章中,我們已經對Bean的生命週期做了簡單的介紹,主要介紹了整個生命週期中的初始化階段以及基於容器啓動停止時LifeCycleBean的回調機制,另外對Bean的銷燬過程也做了簡單介紹。但是對於整個Bean的生命週期,這還只是一小部分,在這篇文章中,我們將學習完成剩下部分的學習,同時對之前的內容做一次複習。整個Bean的生命週期,按照我們之前的介紹,可以分爲四部分

  • 實例化
  • 屬性注入
  • 初始化
  • 銷燬

本文主要介紹實例化及屬性注入階段

生命週期概念補充

雖然我們一直說整個Bean的生命週期分爲四個部分,但是相信很多同學一直對Bean的生命週期到底從哪裏開始,到哪裏結束沒有一個清晰的概念。可能你會說,不就是從實例化開始,到銷燬結束嗎?當然,這並沒有錯,但是具體什麼時候算開始實例化呢?什麼時候又算銷燬呢?這個問題你是否能清楚的回答呢?如果不能,請繼續往下看。

筆者認爲,整個Spring中Bean的生命週期,從第一次調用後置處理器中的applyBeanPostProcessorsBeforeInstantiation方法開始的,這個方法見名知意,翻譯過來就是在實例化之前調用後置處理器applyBeanPostProcessorsAfterInitialization方法的調用,意味着Bean的生命週期中創建階段的結束。對於銷燬沒有什麼歧義,就是在調用對應Bean的銷燬方法就以爲着這個Bean走到了生命的盡頭,標誌着Bean生命週期的結束。那麼結合上篇文章中的結論,我現在把Bean的生命週期的範圍界定如下:

在這裏插入圖片描述

需要注意的是,對於BeanDefinion的掃描,解析,驗證並不屬於Bean的生命週期的一部分。這樣清晰的界定Bean的生命週期的概念是很有必要的,也許剛剛開始對於我們而言,Bean的生命週期就是一團亂麻,但是至少現在我們已經抓住了線頭。而整個Bean的生命週期,我將其分爲了兩部分

  • 創建
  • 銷燬

對於銷燬階段,我們不需要過多關注,對於創建階段,開始的標誌行爲爲:applyBeanPostProcessorsBeforeInstantiation方法執行,結束的標誌行爲爲:applyBeanPostProcessorsAfterInitialization方法執行。

基於上面的結論,我們開始進行接下來的分析對於本文中代碼的分析,我們還是參照下面這個圖

在這裏插入圖片描述

實例化

整個實例化的過程主要對於上圖中的3-11-6-4createBean)以及3-11-6-4-1doCreateBean)步驟

createBean流程分析

代碼如下:

protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		RootBeanDefinition mbdToUse = mbd;
		
    // 第一步:解析BeanDefinition中的beanClass屬性
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}
    
		try {
            // 第二步:處理lookup-method跟replace-method,判斷是否存在方法的重載
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			// 第三步:判斷這個類在之後是否需要進行AOP代理
			Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
			if (bean != null) {
				return bean;
			}
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
					"BeanPostProcessor before instantiation of bean failed", ex);
		}

		try {
            // 開始創建Bean
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}

可以看到,第一步第二步還是在對BeanDefinition中的一些屬性做處理,它並不屬於我們Bean的生命週期的一部分,我們直接跳過,接下來看第三步的代碼:

protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
    Object bean = null;
    if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
        // 不是合成類,並且有實例化後置處理器。這個判斷基本上恆成立
        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
            // 獲取這個BeanDefinition的類型
            Class<?> targetType = determineTargetType(beanName, mbd);
            if (targetType != null) {
                // 這裏執行的主要是AbstractAutoProxyCreator這個類中的方法,決定是否要進行AOP代理
                bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
                // 這裏執行了一個短路操作,如果在這個後置處理中直接返回了一個Bean,那麼後面相關的操作就不會執行了,只會執行一個AOP的代理操作
                if (bean != null) {
                    // 雖然這個Bean被短路了,意味着不需要經過後面的初始化階段,但是如果需要代理的話,還是要進行AOP代理,這個地方的短路操作只是意味着我們直接在後置處理器中提供了一個準備充分的的Bean,這個Bean不需要進行初始化,但需不需要進行代理,任然由AbstractAutoProxyCreator的applyBeanPostProcessorsBeforeInstantiation方法決定。在這個地方還是要調用一次Bean的初始化後置處理器保證Bean被完全的處理完
                    bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
                }
            }
        }
        // bean != null基本會一直返回false,所以beforeInstantiationResolved這個變量也會一直爲false
        mbd.beforeInstantiationResolved = (bean != null);
    }
    return bean;
}

對於AbstractAutoProxyCreatorapplyBeanPostProcessorsBeforeInstantiation這個方法的分析我們暫且不管,等到AOP學習階段在進行詳細分析。我們暫且只需要知道這個方法會決定在後續中要不要爲這個Bean產生代理對象

doCreateBean流程分析

	protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {

		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
            // 第一步:單例情況下,看factoryBeanInstanceCache這個緩存中是否有
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
            // 第二步:這裏創建對象
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                    // 第三步:後置處理器處理
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					// 省略異常處理
				}
				mbd.postProcessed = true;
			}
		}
		
        // 循環引用相關,源碼閱讀階段再來解讀這段代碼,暫且就關注以下後置處理器的調用時機
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			// 第四步:調用後置處理器,早期曝光一個工廠對象
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		Object exposedObject = bean;
		try {
            // 第五步:屬性注入
			populateBean(beanName, mbd, instanceWrapper);
            // 第六步:初始化
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				// 省略異常處理
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						// 省略異常處理
					}
				}
			}
		}

		try {
            // 第七步:註冊需要銷燬的Bean,放到一個需要銷燬的Map中(disposableBeans)
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			// 省略異常處理
		}

		return exposedObject;
	}
第一步:factoryBeanInstanceCache什麼時候不爲空?
if (mbd.isSingleton()) {
    // 第一步:單例情況下,看factoryBeanInstanceCache這個緩存中是否有
    instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}

這段代碼深究起來很複雜,我這裏就單純用理論解釋下:

假設我們現在有一個IndexService,它有一個屬性A,代碼如下:

@Component
public class IndexService {
	@Autowired
	A a;

	public A getA() {
		return a;
	}
}

而這個A又是採用FactroyBean的形式配置的,如下:

@Component
public class MyFactoryBean implements SmartFactoryBean {
	@Override
	public A getObject() throws Exception {
		return new A();
	}
	@Override
	public Class<?> getObjectType() {
		return A.class;
	}
    // 這個地方並不一定要配置成懶加載,這裏只是爲了讓MyFactoryBean這個Bean在IndexService之後實例化
	@Override
	public boolean isEagerInit() {
		return false;
	}
}

我們思考一個問題,在上面這種場景下,當IndexService要完成屬性注入時,Spring會怎麼做呢?

Spring現在知道IndexService要注入一個類型爲A的屬性,所以它會遍歷所有的解析出來的BeanDefinition,然後每一個BeanDefinition中的類型是不是A類型,類似下面這樣:

for (String beanName : this.beanDefinitionNames) {
	// 1.獲取BeanDefinition
    // 2.根據BeanDefinition中的定義判斷是否是一個A
}

上面這種判斷大部分情況下是成立的,但是對於一種特殊的Bean是不行的,就是我們之前介紹過的FactoryBean,因爲我們配置FactoacryBean的目的並不是直接使用FactoryBean這個Bean自身,而是想要通過它的getObject方法將一個對象放到Spring容器中,所以當我們遍歷到一個BeanDefinition,並且這個BeanDefinition是一個FactoacryBean時就需要做特殊處理,我們知道FactoacryBean中有一個getObjectType方法,通過這個方法我們可以得到要被這個FactoacryBean創建的對象的類型,如果我們能調用這個方法的話,那麼我們就可以來判斷這個類型是不是一個A了。

但是,在我們上面的例子中,這個時候MyFactoryBean還沒有被創建出來。所以Spring在這個時候會去實例化這個MyFactoryBean,然後調用其getObjectType方法,再做類型判斷,最後進行屬性注入,僞代碼如下:

for (String beanName : this.beanDefinitionNames) {
	// 1.獲取BeanDefinition
    // 2.如果不是一個FactoacryBean,直接根據BeanDefinition中的屬性判斷
    if(不是一個FactoacryBean){
        //直接根據BeanDefinition中的屬性判斷是不是A
    }
    // 3.如果是一個FactoacryBean
    if(是一個FactoacryBean){
        // 先創建這個FactoacryBean,然後再調用getObjectType方法了
    }
}

大家可以根據我們上面的代碼自己調試,我這裏就不放debug的截圖了。

第二步:創建對象(createBeanInstance)
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 獲取到解析後的beanClass
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		
    	// 忽略異常處理
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		
    	// 獲取工廠方法,用於之後創建對象 
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// 原型情況下避免多次解析
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// 跟後置處理器相關,我們主要關注這行代碼
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// 默認使用無參構造函數創建對象
		return instantiateBean(beanName, mbd);
	}

在創建對象的時候,其餘的代碼我們暫時不做過多關注。我們暫且知道在創建對象的過程中,Spring會調用一個後置處理器來推斷構造函數。

第三步:applyMergedBeanDefinitionPostProcessors

應用合併後的BeanDefinition,Spring自身利用這點做了一些註解元數據的緩存。

我們就以AutowiredAnnotationBeanPostProcessor這個類的對應方法看一下其大概作用

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
    // 這個方法就是找到這個正在創建的Bean中需要注入的字段,並放入緩存中
    InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
    metadata.checkConfigMembers(beanDefinition);
}
第四步:getEarlyBeanReference
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                // 在這裏保證注入的對象是一個代理的對象(如果需要代理的話),主要用於循環依賴
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

屬性注入

第五步:屬性注入(populateBean)
	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				// 省略異常
			}
			else {
				return;
			}
		}

		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {			// 主要判斷之後是否需要進行屬性注入
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		
        // 自動注入模型下,找到合適的屬性,在後續方法中再進行注入
		if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);

		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 精確注入下,在這裏完成屬性注入
					PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
                    // 一般不會進行這個方法
					if (pvsToUse == null) {
						if (filteredPds == null) {
							filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
						}
						pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvsToUse == null) {
							return;
						}
					}
					pvs = pvsToUse;
				}
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}

		if (pvs != null) {
            // XML配置,或者自動注入,會將之前找到的屬性在這裏進行注入
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

在上面整個流程中,我們主要關注一個方法,postProcessProperties,這個方法會將之前通過postProcessMergedBeanDefinition方法找到的注入點,在這一步進行注入。完成屬性注入後,就開始初始化了,初始化的流程在上篇文章中已經介紹過了,這裏就不再贅述了。

總結

在這兩篇文章中,我們已經對Bean的全部的生命週期做了詳細分析,當然,對於一些複雜的代碼,暫時還沒有去深究,因爲之後打算寫一系列專門的源碼分析文章。大家可以關注我後續的文章。對於整個Bean的生命週期可以總結畫圖如下

在這裏插入圖片描述

首先,整個Bean的生命週期我們將其劃分爲兩個部分

  1. 創建
  2. 銷燬

對於創建階段,我們又將其分爲三步

  • 實例化
  • 屬性注入
  • 初始化

我們可以看到,在整個過程中BeanPostPorcessor穿插執行,輔助Spring完成了整個Bean的生命週期。

掃描下方二維碼,關注我的公衆號,更多精彩文章在等您!~~

公衆號

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