Spring原始碼系列:依賴注入(一)getBean

glmapper發表於2018-02-03

Spring原始碼系列:BeanFactory的建立文章中我們談到了BeanFactory這容器,這個裡面提供了注入的實現介面。其具體的實現還需要從AbstractBeanFactory和DefaultListableBeanFactory中來看。今天就先擼一下AbstractBeanFactory這個類中的getBean這個方法。

1、getBean方法

getBean提供了四個過載方法,如下:

//通過name獲取Bean
@Override
public Object getBean(String name) throws BeansException {
	return doGetBean(name, null, null, false);
}
//通過name和型別獲取Bean
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
	return doGetBean(name, requiredType, null, false);
}
//通過name和物件引數獲取Bean
@Override
public Object getBean(String name, Object... args) throws BeansException {
	return doGetBean(name, null, args, false);
}
//通過name、型別和引數獲取Bean
public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException {
	return doGetBean(name, requiredType, args, false);
}
複製程式碼

從這四個過載方法的方法體中可以看出,他們都是通過doGetBean來實現的。所以doGetBean其實才是真正獲取Bean的地方,也是觸發依賴注入發生的地方。(這個方法比較長,分段來說)

2、doGetBean

先來看下方法的定義:

@SuppressWarnings("unchecked")
	protected <T> T doGetBean(
	final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
	throws BeansException {
複製程式碼
  • name 要檢索的bean的名稱
  • requiredType 要檢索的bean所需的型別
  • args 使用顯式引數建立bean例項時使用的引數(僅在建立新例項時應用,而不是在檢索現有例項時應用)
  • typeCheckOnly 是否為型別檢查而獲得例項,而不是實際使用
//返回bean名稱,剝離工廠引用字首,並將別名解析為規範名稱。
final String beanName = transformedBeanName(name);
//宣告當前需要返回的bean物件
Object bean;

// 先從快取中獲取bean,處理已經被建立的單例模式的bean,
//對於此類bean的請求不需要重複的建立(singleton)
Object sharedInstance = getSingleton(beanName);
複製程式碼

如果當前獲取到的sharedInstance不為null並且引數為空,則進行FactoryBean的相關處理,並獲取FactoryBean的處理結果。

if (sharedInstance != null && args == null) {
	if (logger.isDebugEnabled()) {
	    //返回指定的singleton bean是否正在建立(在整個工廠內)。
		if (isSingletonCurrentlyInCreation(beanName)) {
			logger.debug("Returning eagerly cached instance of singleton bean '" 
			+ beanName +"' that is not fully initialized yet - a consequence of a circular reference");
		}
		else {
			logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
		}
	}
	//完成FactoryBean的相關處理,並用來獲取FactoryBean的處理結果
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
複製程式碼

如果當前獲取到的sharedInstance為null,我們再來看下做了哪些處理(下面的都在一個大的else裡面):

else {
    //分解到下面
}
複製程式碼
//在當前執行緒中,返回指定的prototype bean是否正在建立。
if (isPrototypeCurrentlyInCreation(beanName)) {
	throw new BeanCurrentlyInCreationException(beanName);
}
複製程式碼

下面這段的作用是對Ioc容器中的BeanDefinition是否存在進行檢測,先是檢測當前BeanFactory中是否能夠獲取到,如果取不到則繼續到雙親容器中進行嘗試獲取,如果雙親還是取不到,則繼續向上一級父容器中嘗試獲取。

// 檢查該工廠是否存在bean定義。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
	// 如果沒有,則繼續檢查父類
	String nameToLookup = originalBeanName(name);
	if (args != null) {
		// 用明確的引數代表父項。
		return (T) parentBeanFactory.getBean(nameToLookup, args);
	}
	else {
		// 如果沒有args - >委託給標準的getBean方法。
		return parentBeanFactory.getBean(nameToLookup, requiredType);
	}
}
複製程式碼

將指定的bean標記為已經建立(或即將建立);這裡允許bean工廠優化其快取以重複建立指定的bean。

if (!typeCheckOnly) {
	markBeanAsCreated(beanName);
}
複製程式碼

先根據beanName來獲取BeanDefinition,然後獲取當前bean的所有依賴bean,這裡是通過遞迴呼叫getBean來完成,直到沒有任何依賴的bean為止。

final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
//檢查給定的合併bean定義,可能丟擲驗證異常。
checkMergedBeanDefinition(mbd, beanName, args);
// 保證當前bean依賴的bean的初始化。
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
	for (String dep : dependsOn) {
		if (isDependent(beanName, dep)) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
			"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
		}
		registerDependentBean(dep, beanName);
		//遞迴處理依賴bean
		getBean(dep);
	}
}
複製程式碼

下面這段就是建立一個bean例項;這裡通過呼叫getSingleton方法來建立一個單例bean例項;從程式碼中可以看到,getSingleton的呼叫是通過getObject這個回撥函式來間接呼叫createBean完成的。

if (mbd.isSingleton()) {
	sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
	//回撥函式getObject
		@Override
		public Object getObject() throws BeansException {
			try {
			    //建立bean
				return createBean(beanName, mbd, args);
			}
			catch (BeansException ex) {
				//發生異常則銷燬
				destroySingleton(beanName);
				throw ex;
			}
		}
	});
	//獲取給定bean例項的物件,無論是bean例項本身,還是FactoryBean建立的物件。
	bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
複製程式碼

下面是建立prototype bean

else if (mbd.isPrototype()) {
    Object prototypeInstance = null;
    try {
    	beforePrototypeCreation(beanName);
    	//建立prototype bean
    	prototypeInstance = createBean(beanName, mbd, args);
    }
    finally {
    	afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
複製程式碼

最後是對建立的bean進行型別檢查,沒有問題就返回已經建立好的bean;此時這個bean是包含依賴關係的bean

if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
	try {
		return getTypeConverter().convertIfNecessary(bean, requiredType);
	}
	catch (TypeMismatchException ex) {
		if (logger.isDebugEnabled()) {
			logger.debug("Failed to convert bean '" + name + "' to required type '" +
					ClassUtils.getQualifiedName(requiredType) + "'", ex);
		}
		throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
	}
}
//返回bean
return (T) bean;
複製程式碼

getBean是依賴注入的起點,從上面的分析可以看出,bean的建立都是通過createBean來完成具體的建立的。createBean的具體實現是在AbstractAutowireCapableBeanFactory中的,這裡createBean不僅僅負責建立bean,還需要完成對bean的初始化。

相關文章