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

Spring源碼系列:BeanFactory的建立文章中咱們談到了BeanFactory這容器,這個裏面提供了注入的實現接口。其具體的實現還須要從AbstractBeanFactory和DefaultListableBeanFactory中來看。今天就先擼一下AbstractBeanFactory這個類中的getBean這個方法。java

一、getBean方法緩存

getBean提供了四個重載方法,以下:bash

//經過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的地方,也是觸發依賴注入發生的地方。(這個方法比較長,分段來講)ide

二、doGetBean函數

先來看下方法的定義:post

@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裏面):ui

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

下面這段的做用是對Ioc容器中的BeanDefinition是否存在進行檢測,先是檢測當前BeanFactory中是否可以獲取到,若是取不到則繼續到雙親容器中進行嘗試獲取,若是雙親仍是取不到,則繼續向上一級父容器中嘗試獲取。spa

// 檢查該工廠是否存在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。prototype

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的初始化。

相關文章
相關標籤/搜索