1. 程式人生 > 程式設計 >Spring5原始碼解析9-doGetBean概述

Spring5原始碼解析9-doGetBean概述

接上回,AbstractApplicationContext#refresh呼叫AbstractApplicationContext#finishBeanFactoryInitialization來初始化所有的非懶載入單例 Bean。在該AbstractApplicationContext#finishBeanFactoryInitialization方法內部通過呼叫AbstractBeanFactory#doGetBean來獲取 Spring 容器所管理的 Bean。

AbstractBeanFactory#doGetBean

AbstractBeanFactory#doGetBean原始碼如下:

protected <T> T doGetBean(final String name,@Nullable final Class<T> requiredType,@Nullable final Object[] args,boolean typeCheckOnly) throws BeansException {

	// 如果這個 name 是 FactoryBean 的beanName (&+beanName),就刪除&,返回beanName,傳入的name也可以是別名,也需要做轉換
	// 注意 beanName 和 name 變數的區別,beanName是經過處理的,經過處理的beanName就直接對應singletonObjects中的key
final String beanName = transformedBeanName(name); Object bean; // Eagerly check singleton cache for manually registered singletons. // 根據beanName嘗試從singletonObjects獲取Bean // 獲取不到則再嘗試從earlySingletonObjects,singletonFactories 從獲取Bean // 這段程式碼和解決迴圈依賴有關 Object sharedInstance = getSingleton(beanName); // 第一次進入sharedInstance肯定為null
if (sharedInstance != null && args == null) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { logger.trace("Returning eagerly cached instance of singleton bean '" + beanName + "' that is not fully initialized yet - a consequence of a circular reference"); } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); } } // 如果sharedInstance不為null,也就是非第一次進入 // 為什麼要呼叫 getObjectForBeanInstance 方法,判斷當前Bean是不是FactoryBean,如果是,那麼要不要呼叫getObject方法 // 因為傳入的name變數如果是(&+beanName),那麼beanName變數就是(beanName),也就是說,程式在這裡要返回FactoryBean // 如果傳入的name變數(beanName),那麼beanName變數也是(beanName),但是,之前獲取的sharedInstance可能是FactoryBean,需要通過sharedInstance來獲取對應的Bean // 如果傳入的name變數(beanName),獲取的sharedInstance就是對應的Bean的話,就直接返回Bean bean = getObjectForBeanInstance(sharedInstance,name,beanName,null); } else { // Fail if we're already creating this bean instance: // We're assumably within a circular reference. // 判斷是否迴圈依賴 if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } // Check if bean definition exists in this factory. // 獲取父BeanFactory,一般情況下,父BeanFactory為null,如果存在父BeanFactory,就先去父級容器去查詢 BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { // Not found -> check parent. String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup,requiredType,args,typeCheckOnly); } else if (args != null) { // Delegation to parent with explicit args. return (T) parentBeanFactory.getBean(nameToLookup,args); } else if (requiredType != null) { // No args -> delegate to standard getBean method. return parentBeanFactory.getBean(nameToLookup,requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } // 建立的Bean是否需要進行型別驗證,一般情況下都不需要 if (!typeCheckOnly) { // 標記 bean 已經被建立 markBeanAsCreated(beanName); } try { // 獲取其父類Bean定義,子類合併父類公共屬性 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd,args); // Guarantee initialization of beans that the current bean depends on. // 獲取當前Bean依賴的Bean的名稱,@DependsOn String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null) { for (String dep : dependsOn) { if (isDependent(beanName,dep)) { throw new BeanCreationException(mbd.getResourceDescription(),"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'"); } // 如果當前Bean依賴其他Bean,把被依賴Bean註冊給當前Bean registerDependentBean(dep,beanName); try { // 先去建立所依賴的Bean getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException(mbd.getResourceDescription(),"'" + beanName + "' depends on missing bean '" + dep + "'",ex); } } } // Create bean instance. if (mbd.isSingleton()) { // 建立單例Bean sharedInstance = getSingleton(beanName,() -> { try { return createBean(beanName,mbd,args); } catch (BeansException ex) { // Explicitly remove instance from singleton cache: It might have been put there // eagerly by the creation process,to allow for circular reference resolution. // Also remove any beans that received a temporary reference to the bean. destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance,mbd); } else if (mbd.isPrototype()) { // It's a prototype -> create a new instance. // 建立prototype Bean,每次都會建立一個新的物件 Object prototypeInstance = null; try { // 回撥beforePrototypeCreation方法,註冊當前建立的原型物件 beforePrototypeCreation(beanName); // 建立物件 prototypeInstance = createBean(beanName,args); } finally { // 回撥 afterPrototypeCreation 方法,告訴容器該Bean的原型物件不再建立 afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance,mbd); } else { // 如果既不是單例Bean,也不是prototype,則獲取其Scope String scopeName = mbd.getScope(); final Scope scope = this.scopes.get(scopeName); if (scope == null) { throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'"); } try { // 建立物件 Object scopedInstance = scope.get(beanName,() -> { beforePrototypeCreation(beanName); try { return createBean(beanName,args); } finally { afterPrototypeCreation(beanName); } }); bean = getObjectForBeanInstance(scopedInstance,mbd); } catch (IllegalStateException ex) { throw new BeanCreationException(beanName,"Scope '" + scopeName + "' is not active for the current thread; consider " + "defining a scoped proxy for this bean if you intend to refer to it from a singleton",ex); } } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } // Check if required type matches the type of the actual bean instance. // 對建立的Bean進行型別檢查 if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean,requiredType); if (convertedBean == null) { throw new BeanNotOfRequiredTypeException(name,bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'",ex); } throw new BeanNotOfRequiredTypeException(name,bean.getClass()); } } return (T) bean; } 複製程式碼

主要流程都已經在上述的原始碼中增加了註釋,讀者可以自己查閱。其中,我覺得最主要是要明白以下幾點:

Object sharedInstance = getSingleton(beanName);

Object sharedInstance = getSingleton(beanName);這段程式碼是解決迴圈依賴的關鍵,先大概看一下,留個印象,具體的等後面有空講一下迴圈依賴吧。

public Object getSingleton(String beanName) {
	return getSingleton(beanName,true);
}

//getSingleton(beanName,true);原始碼
@Nullable
protected Object getSingleton(String beanName,boolean allowEarlyReference) {
	//singletonObjects 就是Spring內部用來存放單例Bean的物件池,key為beanName,value為Bean
	Object singletonObject = this.singletonObjects.get(beanName);
	// singletonsCurrentlyInCreation 存放了當前正在建立的bean的BeanName
	if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
		synchronized (this.singletonObjects) {
			// earlySingletonObjects 是早期單例Bean的快取池,此時Bean已經被建立(newInstance),但是還沒有完成初始化
			// key為beanName,value為Bean
			singletonObject = this.earlySingletonObjects.get(beanName);
			//是否允許早期依賴
			if (singletonObject == null && allowEarlyReference) {
				//singletonFactories 單例工廠的快取,key為beanName,value 為ObjectFactory
				ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
				if (singletonFactory != null) {
					//獲取早期Bean
					singletonObject = singletonFactory.getObject();
					//將早期Bean放到earlySingletonObjects中
					this.earlySingletonObjects.put(beanName,singletonObject);
					this.singletonFactories.remove(beanName);
				}
			}
		}
	}
	return singletonObject;
}
複製程式碼

transformedBeanName 和 getObjectForBeanInstance 的作用

呼叫doGetBean方法時會傳入name變數,表明需要從容器中獲取那個 Bean。transformedBeanName除了在處理別名之外,這裡會有以下幾種情況:

第一種情況,直接往容器中註冊 Bean。

@Bean
public UserBean userBean() {
	return new UserBean("shen",111);
}
複製程式碼

在這種情況下,name變數如果為userBean,那麼就是要從容器中獲取UserBean物件。

呼叫transformedBeanName方法返回beanName物件的取值userBean

然後根據beanName去容器中獲取相應的Bean,而獲取到的就是UserBean物件。

最後呼叫getObjectForBeanInstance方法,返回的還是UserBean物件。

第二種情況,通過FactoryBean往容器中註冊 Bean

@Bean
public FactoryBean userBean() {
	return new FactoryBean<UserBean>() {
		@Override
		public UserBean getObject() throws Exception {
			return new UserBean("shen",111);
		}

		@Override
		public Class<?> getObjectType() {
			return UserBean.class;
		}
	};
}
複製程式碼

這裡又可以分為兩種情況:

第一種情況:

如果name變數如果為userBean,那麼也要從容器中獲取UserBean物件。

呼叫transformedBeanName方法返回beanName物件的取值為userBean

然後根據beanName去容器中獲取相應的Bean,而獲取到的是FactoryBean物件。

最後呼叫getObjectForBeanInstance方法,發現是從容器中獲取UserBean物件,於是呼叫FactoryBean#getObject返回UserBean物件。

第二種情況:

name變數如果為&userBean,那麼就是要從容器中獲取FactoryBean物件本身。

呼叫transformedBeanName方法返回beanName物件的取值為userBean

然後根據beanName去容器中獲取相應的Bean,而獲取到的是FactoryBean物件,

最後呼叫getObjectForBeanInstance方法,就是要獲取FactoryBean物件,於是方法返回FactoryBean物件。

@DependsOn

通過原始碼可以知道,Spring 在建立 Bean 之前,首先會建立當前 Bean 所有依賴的 Bean。

String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
	for (String dep : dependsOn) {
		if (isDependent(beanName,dep)) {
			throw new BeanCreationException(mbd.getResourceDescription(),"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
		}
		// 如果當前Bean依賴其他Bean,把被依賴Bean註冊給當前Bean
		registerDependentBean(dep,beanName);
		try {
			// 先去建立所依賴的Bean
			getBean(dep);
		} catch (NoSuchBeanDefinitionException ex) {
			throw new BeanCreationException(mbd.getResourceDescription(),ex);
		}
	}
}
複製程式碼

那什麼是當前 Bean 所有依賴的 Bean 呢?也就是說,String[] dependsOn = mbd.getDependsOn();什麼情況下這個陣列中會有值呢?

在 Spring 中有這個一個註解:@DependsOn。這個註解一般用的很少(碰巧最近專案中用到了這個註解,哈哈哈)。來看一下 Spring 檔案中是怎麼描述的:

Beans on which the current bean depends. Any beans specified are guaranteed to be created by the container before this bean. Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments,but rather depends on the side effects of another bean's initialization. A depends-on declaration can specify both an initialization-time dependency and,in the case of singleton beans only,a corresponding destruction-time dependency. Dependent beans that define a depends-on relationship with a given bean are destroyed first,prior to the given bean itself being destroyed. Thus,a depends-on declaration can also control shutdown order.

機器翻譯:當前 bean 所依賴的 bean。任何指定的 bean 都保證在此 bean 之前由容器建立。當一個 bean 不是通過屬性或建構函式引數顯式依賴於另一個 bean,而是依賴於另一個 bean 初始化的副作用時,很少使用。依賴項宣告既可以指定初始化時間依賴項,也可以指定(在只有單例 bean 的情況下)對應的銷燬時間依賴項。在銷燬給定 bean 之前,首先銷燬定義與給定 bean 的依賴關係的依賴 bean。因此,依賴宣告也可以控制關機順序。

舉個例子

@Service
public class OrderService {

	public OrderService() {
		System.out.println("OrderService create");
	}


	@PreDestroy
	public void destroy() {
		System.out.println("OrderService destroy");
	}
}
複製程式碼
@DependsOn("orderService")
@Service
public class UserService {

	public UserService() {
		System.out.println("UserService create");
	}


	@PreDestroy
	public void destroy() {
		System.out.println("UserService destroy");
	}
}
複製程式碼
@Configuration
@ComponentScan
public class DependsOnMain {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context =
				new AnnotationConfigApplicationContext(DependsOnMain.class);
		context.close();
	}
}
複製程式碼
//執行結果
OrderService create
UserService create
UserService destroy
OrderService destroy
複製程式碼

createBean(beanName,args);

在 Spring 中存在者多種 scope,Spring 會根據不用的 scope 選用不同的初始化方式。但是,不管怎麼樣,Spring 在底層建立 Bean 的時候都是通過呼叫AbstractAutowireCapableBeanFactory#createBean方法來建立物件的。

那 Spring 究竟是怎麼建立 Bean 的呢?AbstractAutowireCapableBeanFactory#createBean方法內部到底做了什麼事情呢?迴圈依賴該怎麼解決呢?

未完待續...


原始碼註釋 GITHUB 地址:github.com/shenjianeng…