Spring原始碼系列:依賴注入(二)createBean

glmapper發表於2018-02-05

Spring原始碼系列:依賴注入(一)(AbstractBeanFactory-getBean)最後說道getBean是依賴注入的起點,bean的建立都是通過createBean來完成具體的建立的。createBean的具體實現是在AbstractAutowireCapableBeanFactory中的。本篇就捋一捋這個方法看下bean的建立過程。

這個方法是AbstractAutowireCapableBeanFactory這個類的中心方法,其作用就是建立一個bean例項,填充bean例項,後置處理等。

在createBean中主要做了三件事:

  • 判斷需要建立的Bean是否可以例項化,這個類是否可以通過類裝載器來載入
  • 是否配置了後置處理器相關處理(如果配置了則返回一個代理)
  • 建立Bean

具體來看方法:

protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
	if (logger.isDebugEnabled()) {
		logger.debug("Creating instance of bean '" + beanName + "'");
	}
	RootBeanDefinition mbdToUse = mbd;
	// Make sure bean class is actually resolved at this point, and
	// clone the bean definition in case of a dynamically resolved Class
	// which cannot be stored in the shared merged bean definition.
	//判斷需要建立的Bean是否可以例項化,這個類是否可以通過類裝載器來載入
	Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
	if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
		mbdToUse = new RootBeanDefinition(mbd);
		mbdToUse.setBeanClass(resolvedClass);
	}

	// Prepare method overrides.
	try {
		mbdToUse.prepareMethodOverrides();
	}
	catch (BeanDefinitionValidationException ex) {
		//異常:Validation of method overrides failed
	}

	try {
		// Give BeanPostProcessors a chance to return a proxy instead of the target 
		//bean instance.
		//是否配置了後置處理器相關處理(如果配置了則返回一個代理)
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
	}
	catch (Throwable ex) {
	    //異常:BeanPostProcessor before instantiation of bean failed
	}
    //建立Bean
	Object beanInstance = doCreateBean(beanName, mbdToUse, args);
	if (logger.isDebugEnabled()) {
		logger.debug("Finished creating instance of bean '" + beanName + "'");
	}
	return beanInstance;
}
複製程式碼

從上面的程式碼中可以看到,建立bean是交給doCreateBean方法來建立的。繼續看doCreateBean這個方法: (這裡面涉及到一個BeanWrapper這個介面,小夥伴可以移步瞭解一下《Spring原始碼系列:BeanWrapper》)

程式碼 1:

// 用BeanWrapper來持有建立出來的Bean物件
BeanWrapper instanceWrapper = null;
//如果是單例的話,則先把快取中的同名bean清除
if (mbd.isSingleton()) {
	instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
//實際建立的交給createBeanInstance來完成,
//bean的生成,這裡會使用預設的類生成器,包裝成BeanWrapperImpl類,
//為了下面的populateBean方法的屬性注入做準備  
if (instanceWrapper == null) {
	instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
複製程式碼

程式碼 2:

允許後處理器修改合併的bean定義。

synchronized (mbd.postProcessingLock) {
    if (!mbd.postProcessed) {
    	try {
    		applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
    	}
    	catch (Throwable ex) {
    	//異常:Post-processing of merged bean definition failed
    	}
    	mbd.postProcessed = true;
    }
    }
複製程式碼

程式碼 3 :

即使被BeanFactoryAware等生命週期介面觸發,也要儘快地快取singletons 以便能夠解析迴圈引用。

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
		isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
	if (logger.isDebugEnabled()) {
		logger.debug("Eagerly caching bean '" + beanName +
				"' to allow for resolving potential circular references");
	}
	addSingletonFactory(beanName, new ObjectFactory<Object>() {
		@Override
		public Object getObject() throws BeansException {
			return getEarlyBeanReference(beanName, mbd, bean);
		}
	});
}
複製程式碼

程式碼 4:

這裡是對bean的初始化的地方,一般情況下依賴注入就在這裡發生;這個exposedObject變數儲存的是在初始化處理完以後返回的作為依賴注入完成之後的bean。

// Initialize the bean instance.
Object exposedObject = bean;
try {
	populateBean(beanName, mbd, instanceWrapper);
	if (exposedObject != null) {
		exposedObject = initializeBean(beanName, exposedObject, mbd);
	}
}
catch (Throwable ex) {
    //丟擲
	if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException)
	    ex).getBeanName())) {
		throw (BeanCreationException) ex;
	}
	else {
	//異常:Initialization of bean failed
	}
}
複製程式碼

程式碼 5:

這裡是註冊bean

try {
	registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
    //異常處理
}
//返回結果
return exposedObject;
複製程式碼

上面的5個程式碼段均是doCreateBean中的處理邏輯,有興趣的小夥伴可以自行查閱原始碼。從上面的程式碼中我們依然沒有得到具體建立的過程,因為在doCreateBean中又依賴:createBeanInstancepopulateBean兩個方法。

createBeanInstance中生成了Bean所包含的java物件。來看是怎麼生成的:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
	// 確保bean類實際上已經解析過了,可以例項化
	Class<?> beanClass = resolveBeanClass(mbd, beanName);

	if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
		//異常:Bean class isn't public, and non-public access not allowed:beanName
	}
     //1. 使用工廠方法來進行bean的例項化
	if (mbd.getFactoryMethodName() != null)  {
		return instantiateUsingFactoryMethod(beanName, mbd, args);
	}

	// 重新建立相同的bean時快捷方式...
	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);
		}
	}

	// 2.需要確定建構函式...,使用建構函式進行bean例項化
	Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
	if (ctors != null ||
			mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
			mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
		return autowireConstructor(beanName, mbd, ctors, args);
	}

	//3.沒有特殊的處理:只需使用無引數建構函式。(預設建構函式)
	return instantiateBean(beanName, mbd);
}
複製程式碼

從上面這段程式碼可以看出,物件的生成有許多不同的方式,有通過工廠的,也有通過容器的autowire特性生成的。當然這些生成方式都是由相關的BeanDefinition來指定的。

Spring中配置Bean的方式我們常用的一種是通過xml檔案來配置,還有就是通過註解的方式來配置

  • demo1
<bean id="user" class="com.glmapper.test.User">
  <property name="name" value="glmapper"></property>       
</bean>
複製程式碼

這種方式,通過class提供的許可權定名,spring就可以利用反射機制建立這個bean。

  • demo2
<bean id="user" class="com.glmapper.test.UserFactory" factory-method="getUser">
    <constructor-arg value="glmapper"></constructor-arg>           
</bean>
複製程式碼

這種是利用靜態工廠方法來建立的,提供的class並非是類的許可權定名, 而是靜態工廠的全類名;除此之外還需要指定獲取bean的方法(此處是getUser)和引數(引數是glmapper)。

  • demo3
<bean id="userFactory" class="com.glmapper.test.UserInstanceFactory">
    <!--用一個集合來儲存我當前的物件例項-->
    <property name="map">
        <map>
            <entry key="user1">
                <bean class="com.glmapper.test.User">
                    <property name="name" value="glmapper1"></property>        
                </bean>
            </entry>    

            <entry key="user2">
                <bean class="com.glmapper.test.User">
                    <property name="name" value="glmapper2"></property>   
                </bean>
            </entry>
        </map>  
    </property>
 </bean>
 
 //例項1
 <bean id="user1" factory-bean="userFactory" factory-method="getUserInstance">
    <constructor-arg value="user1"></constructor-arg>           
 </bean>
//例項2
 <bean id="user2" factory-bean="userFactory" factory-method="getUserInstance">
    <constructor-arg value="user2"></constructor-arg>           
 </bean
複製程式碼

這種方式和靜態工廠的區別在於我們需要先例項化一個工廠物件,然後才能使用這個工廠物件來建立我們的bean。getUserInstance通過key值來獲取我們已經例項化好的物件(當然方式有很多,此處以map來舉個例子)。關於註解的和使用FactoryBean介面的這裡就暫時不說,後期再聊

OK,繼續來分鐘,上面說到的是以工廠方法建立bean,具體的原始碼有點長,這裡就不放了,大概思路就如上面所提到的那幾種方式。接下來看下常見的使用instantiateBean方式(使用它的預設建構函式)來構建bean的程式碼:

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
	try {
		Object beanInstance;
		final BeanFactory parent = this;
	    //獲取系統安全介面。
	    //如果已經為當前應用程式建立了安全管理器,則返回該安全管理器; 
	    //否則,返回null。
		if (System.getSecurityManager() != null) {
			beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					return getInstantiationStrategy().instantiate(mbd, beanName, parent);
				}
			}, getAccessControlContext());
		}
		else {
			beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
		}
		BeanWrapper bw = new BeanWrapperImpl(beanInstance);
		initBeanWrapper(bw);
		return bw;
	}
	catch (Throwable ex) {
		//異常:Instantiation of bean failed
	}
}
複製程式碼

可以看出,上面的建立都是通過:

getInstantiationStrategy().instantiate(mbd, beanName, parent);
複製程式碼

這樣一段程式碼來完成的,是的,這裡已經快接近真相了。從語義上來分析,先是獲取了一種策略,然後利用當前獲取的策略再去執行例項化。OK,我們看下getInstantiationStrategy()拿到的是什麼:

//返回例項化策略用於建立bean例項。
protected InstantiationStrategy getInstantiationStrategy() {
	return this.instantiationStrategy;
}
//預設的例項化測試是使用CGLIB代理
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy();
複製程式碼

看到這裡我們清楚了,預設建構函式的情況下,在spring中會使用Cglib來進行bean的例項化(關於cglib此處不再贅述)。我們看下CglibSubclassingInstantiationStrategy這個類的申明:

public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy 
複製程式碼

它繼承自SimpleInstantiationStrategy ,這個又是什麼鬼呢?

SimpleInstantiationStrategy是Spring用來生成Bean物件的預設類,在這個類中提供了兩種例項化java物件的方法,一種是基於java自身反射機制的BeanUtils,還有一種就是基於Cglib

如何建立的就不說了;到這裡createBeanInstance就說完了(Bean已經建立了);但是僅僅是建立,spring還沒有處理它們,比如說bean物件的屬性,依賴關係等等。這些就是上面提到的另外一個方法populateBean;

這個方法其實就做了一件事:**使用bean定義中的屬性值在給定的BeanWrapper中填充bean例項。**分段來看: 下面這段程式碼是先將BeanDefinition中設定的property值封裝成PropertyValues,然後檢測我們的BeanWrapper是否為Null,如果為null則丟擲異常或者跳過當前空例項賦值階段

//獲取到BeanDefinition中設定的property值,封裝成PropertyValues
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
	if (!pvs.isEmpty()) {
	//異常:Cannot apply property values to null instance
	}
	else {
	// Skip property population phase for null instance.
	    return;
	}
}
複製程式碼

下面這段程式碼的意思是給任何InstantiationAwareBeanPostProcessors提供在設定屬性之前修改bean狀態的機會。

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;
}
複製程式碼

下面就是對具體注入方式的處理:

//處理autowire的注入;可以根據bean的名稱和型別來注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
	mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

    // 則根據名稱新增基於自動裝配的屬性值。
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
    	autowireByName(beanName, mbd, bw, newPvs);
    }
    
    // 根據型別新增基於自動裝配的屬性值。
    if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
    	autowireByType(beanName, mbd, bw, newPvs);
    }
    
    pvs = newPvs;
}
複製程式碼

兩個判斷條件,在滿足的情況下做的處理分別是:

  • 在工廠將給定屬性值應用到給定的bean後,對其進行後處理。 允許檢查所有的依賴關係是否被滿足,例如基於bean屬性設定器上的“Required”註解。還允許替換要應用的屬性值,通常通過建立基於原始PropertyValues的新MutablePropertyValues例項,新增或刪除特定值。
  • 執行依賴性檢查
//返回這個工廠是否擁有一個InstantiationAwareBeanPostProcessor
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
//返回依賴檢查程式碼。
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

if (hasInstAwareBpps || needsDepCheck) {
//從給定的BeanWrapper中提取一組已過濾的PropertyDescriptors,
//不包括在被忽略的依賴性介面上定義的被忽略的依賴型別或屬性(譯註)。
	PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
	if (hasInstAwareBpps) {
    	for (BeanPostProcessor bp : getBeanPostProcessors()) {
        	if (bp instanceof InstantiationAwareBeanPostProcessor) {
        		InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
        		pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
        		if (pvs == null) {
        			return;
        		}
        	}
    	}
	}
	if (needsDepCheck) {
		checkDependencies(beanName, mbd, filteredPds, pvs);
	}
}
複製程式碼

最後是對屬性進行注入:

applyPropertyValues(beanName, mbd, bw, pvs);
複製程式碼

這個方法描述的是對屬性進行解析然後注入的過程;先來分析下applyPropertyValues的申明:

protected void applyPropertyValues(String beanName
, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs)
複製程式碼
  • beanName bean名稱
  • mbd 合併的bean definition
  • bw 包裝目標物件的BeanWrapper
  • pvs 新的屬性值

程式碼分段來看:

  • 引數驗證
if (pvs == null || pvs.isEmpty()) {
	return;
}
複製程式碼
  • pvs引數處理
if (pvs instanceof MutablePropertyValues) {
    mpvs = (MutablePropertyValues) pvs;
    if (mpvs.isConverted()) {
    	// 使用預先轉換後的值。
    	try {
    		bw.setPropertyValues(mpvs);
    		return;
    	}
    	catch (BeansException ex) {
    		//異常:Error setting property values
    	}
    }
    original = mpvs.getPropertyValueList();
    }
    else {
    original = Arrays.asList(pvs.getPropertyValues());
    }
複製程式碼
  • valueResolver來解析BeanDefinition
BeanDefinitionValueResolver valueResolver = 
new BeanDefinitionValueResolver(this, beanName, mbd, converter);
複製程式碼
  • 為解析值建立一個副本,注入到bean中的是副本的資料
// Create a deep copy, resolving any references for values.
List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
複製程式碼
  • 遍歷處理
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
    //返回此持有者是否已經包含轉換後的值(true),還是需要轉換值(false)。
    if (pv.isConverted()) {
    	deepCopy.add(pv);
    }   
    else {
    	String propertyName = pv.getName();
    	Object originalValue = pv.getValue();
    	//看下面的註釋resolveValueIfNecessary
    	Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
    	Object convertedValue = resolvedValue;
    	boolean convertible = bw.isWritableProperty(propertyName) &&
    			!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
    	if (convertible) {
    		convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
    	}
    	// 可能將轉換的值儲存在合併的bean定義中,以避免為每個建立的bean例項重新轉換。
    	if (resolvedValue == originalValue) {
    		if (convertible) {
    			pv.setConvertedValue(convertedValue);
    		}
    		deepCopy.add(pv);
    	}
    	else if (convertible && originalValue instanceof TypedStringValue &&
    			!((TypedStringValue) originalValue).isDynamic() &&
    			!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
    		pv.setConvertedValue(convertedValue);
    		deepCopy.add(pv);
    	}
    	else {
    		resolveNecessary = true;
    		deepCopy.add(new PropertyValue(pv, convertedValue));
    	}
    }
}
複製程式碼
  • resolveValueIfNecessary

    給定一個PropertyValue,返回一個value,必要時解析對工廠中其他bean的引用。value可以是:

    • 一個BeanDefinition,它導致建立一個相應的新的bean例項。 Singleton標誌和這樣的"inner beans"的名字被忽略:內部beans是匿名原型。
    • RuntimeBeanReference(必須解析)
    • ManagedList
    • ManagedSet
    • ManagedMap
    • 一個普通的物件或null,在這種情況下,它是孤立的。

下面這段程式碼時依賴注入發生的地方,其實際上是在BeanWrapperImpl中來完成。

try {
    bw.setPropertyValues(new MutablePropertyValues(deepCopy));
}
catch (BeansException ex) {
    //異常:Error setting property values
}
複製程式碼

上面說到spring是通過BeanDefinitionValueResolver來解析BeanDefinition的,然後再注入到property中,關於這個過程在下一篇中來說。

Spring原始碼系列:依賴注入(二)createBean
歡迎關注微信公眾號

相關文章