從源碼解讀Spring的IOC

概念

IOC(Inversion Of Control),即控制反轉,或者說DI(Dependency Injection),依賴注入,都屬於Spring中的一種特色,能夠統稱爲IOCjava

  • 控制反轉,即控制權的反轉,也就是說將內置對象建立的控制權交給第三方容器,而不是自己的對象
  • 依賴注入,即將依賴對象進行注入,也就是說不主動建立對象,而是經過第三方容器將依賴的對象注入進來

不論是IOC仍是DI,它們都有一個共同的特色,即經過第三方容器來管理對象的建立、初始化、注入、銷燬,在Spring中,這些容器中的對象統稱爲bean,使用的時候只須要經過xml或Java的配置就可以很方便地將一個對象聲明爲容器中的bean,而且能夠經過@Autowired註解等方法將這些bean注入到須要的地方,咱們接下來就要深刻地瞭解一下Spring中IOC究竟是怎麼實現的spring

BeanFactory

顧名思義,BeanFactory就是Bean的工廠,也就是Bean的容器,BeanFactory做爲容器接口,咱們暫不關心它的實現類,先了解一下它自己的特性,點進BeanFactory的源碼,咱們只看如下這幾個重要的方法,其他方法用到的時候再說編程

/** 經過name獲取bean實例 */
	Object getBean(String name) throws BeansException;

	/** 經過name和對象類型獲取bean實例 */
	<T> T getBean(String name, Class<T> requiredType) throws BeansException;

	/** 獲得bean的別名,若是經過別名索引,則原名也會被檢索出 */
	String[] getAliases(String name);
複製代碼

這幾個方法看起來很簡單,別急,這只是在接口中的定義,Spring提供了不少BeanFactory的實現類,好比ApplicationContext等緩存

BeanDefinition

bean固然不能用普通的對象來描述,在spring中,bean被封裝成BeanDefinition,以下: 安全

圖1

Bean資源的加載過程

資源的加載,也能夠是認爲是容器的初始化,能夠分爲如下三個部分:session

  • 定位資源
  • 載入資源
  • 註冊資源

好比XmlWebApplicationContext就是從xml文件中加載資源,咱們這裏以ClassPathXmlApplicationContext爲例,瞭解一下xml文件中的配置是怎麼加載到Spring容器中的多線程

首先是構造方法,以下:併發

/** * @param configLocations 資源路徑 * @param refresh 是否自動刷新容器 * @parent parent 容器的父類 */
	public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {

		super(parent);
		setConfigLocations(configLocations);
		if (refresh) {
			refresh();
		}
	}
複製代碼

先來看這個super(parent),咱們一路找上去,發現每一層都調用了super(parent),直到進入AbstractApplicationContext類中,發現調用了一個this()方法,這個方法詳細以下:app

public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}
複製代碼

從字面上理解,應該是相似設置資源解析器之類的方法,咱們進入這個方法,發現其實際上建立了一個PathMatchingResourcePatternResolver對象,同時設置咱們的最頂層容器爲resourceLoader資源加載器,看到這裏就差很少了解了,super(parent)實際上就是設置了bean的資源加載器ide

咱們接着看setConfigLocations(configLocations)方法,源碼以下:

public void setConfigLocations(@Nullable String... locations) {
		if (locations != null) {
			Assert.noNullElements(locations, "Config locations must not be null");
			this.configLocations = new String[locations.length];
			for (int i = 0; i < locations.length; i++) {
				this.configLocations[i] = resolvePath(locations[i]).trim();
			}
		}
		else {
			this.configLocations = null;
		}
	}
複製代碼

這個方法是繼承而來的,是AbstractRefreshableConfigApplicationContext的一個方法,在這個方法內部,設置了configLocations的值爲資源路徑(進行環境變量填補充並去除空格),能夠理解爲對資源進行定位

也就是說,容器在建立出來時,作了如下兩件事(不包括刷新容器操做):

  • 設置資源解析器
  • 設置資源路徑,進行資源定位

而後咱們再來看這個可選的refresh()方法,這是從AbstractApplicationContext繼承而來的方法,源碼以下:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 獲取當前時間,同時設置同步標識,避免多線程下衝突
			prepareRefresh();

			// 實際調用了子類的refreshBeanFactory方法,同時返回子類的beanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 設置容器屬性
			prepareBeanFactory(beanFactory);

			try {
				// 爲子類beanFactory指定BeanPost事件處理器
				postProcessBeanFactory(beanFactory);

				// 調用註冊爲bean的事件處理器
				invokeBeanFactoryPostProcessors(beanFactory);

				// 註冊BeanPost事件處理器,用於監聽容器建立
				registerBeanPostProcessors(beanFactory);

				// 初始化消息源
				initMessageSource();

				// 初始化事件傳播器
				initApplicationEventMulticaster();

				// 在特定的子類中初始化其餘特殊的bean
				onRefresh();

				// 檢查並註冊監聽器
				registerListeners();

				// 初始化剩餘的單例
				finishBeanFactoryInitialization(beanFactory);

				// 最後一步:初始化容器生命週期處理器,併發布容器生命週期事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 銷燬建立的單例,以免懸置資源
				destroyBeans();

				// 重置同步標識
				cancelRefresh(ex);

				throw ex;
			}

			finally {
				// 由於不須要單例bean中元數據,因此重置spring的自檢緩存
				resetCommonCaches();
			}
		}
	}
複製代碼

配合註釋,就能差很少了解了執行過程,實際就是初始化並註冊一系列處理器和監聽器的過程,有人可能會發現,怎麼沒有加載資源的過程,別急,咱們進入obtainFreshBeanFactory()方法,其中有一個refreshBeanFactory()方法,咱們點開AbstractRefreshableApplicationContext中的實現:

@Override
	protected final void refreshBeanFactory() throws BeansException {
		if (hasBeanFactory()) {
			destroyBeans();
			closeBeanFactory();
		}
		try {
			DefaultListableBeanFactory beanFactory = createBeanFactory();
			beanFactory.setSerializationId(getId());
			customizeBeanFactory(beanFactory);
			loadBeanDefinitions(beanFactory);
			synchronized (this.beanFactoryMonitor) {
				this.beanFactory = beanFactory;
			}
		}
		catch (IOException ex) {
			throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
		}
	}
複製代碼

發現了嗎,這裏有一個loadBeanDefinitions()方法,會根據選用的xml解析仍是註解解析調用子類中的方法,再接下來的解析過程就不是咱們分析的重點了,若是之後有時間,我會再寫一篇來專門分析解析過程的文章

到這裏,整個加載過程就清晰了

依賴注入的過程

一開始,咱們就介紹了getBean(name)方法,那麼咱們接下來,就要詳細的來進行分析這個方法究竟是怎麼把咱們須要的bean建立並交給咱們的

這個方法有兩種常見的實現,AbstractBeanFactory和AbstractApplicationContext,而實際上AbstractApplicationContext也是調用了AbstractBeanFactory的方法,因此咱們就只看AbstractBeanFactory便可

在這個方法內部調用了doGetBean方法,咱們進入方法內部,以下:

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

		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		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 + "'");
				}
			}
			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 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);
				}
			}

			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// Guarantee initialization of beans that the current bean depends on.
				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);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				// Create bean instance.
				if (mbd.isSingleton()) {
					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, name, beanName, mbd);
				}

				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					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, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, 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.
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, 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, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}
複製代碼

整個方法至關之長,咱們分部分來看,先來看第一部分:

// 轉換爲規範名稱(主要針對別名)
		final String beanName = transformedBeanName(name);
		Object bean;

		// 檢查緩存,避免重複建立單例
		Object sharedInstance = getSingleton(beanName);
		// 若是不爲空,就返回緩存中的單例
		if (sharedInstance != null && args == null) {
			// 若是開啓了trace日誌,就根據當前的狀態打印日誌
			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 + "'");
				}
			}
			// 從緩存中返回
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
複製代碼

這個部分至關於一個預檢操做,若是緩存中已經有單例了,就直接返回,避免重複建立

接下來就是真正的建立過程,以下

else {
			// 發現bean正在被建立,說明緩存中已經有原型bean,
			// 多是因爲循環引用致使,這裏拋出異常
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// 查找容器中是否有指定bean的定義
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// ...
			}

			// 判斷是否須要類型驗證,這個值默認爲false
			if (!typeCheckOnly) {
				// 在容器中標記指定的bean已經被建立
				markBeanAsCreated(beanName);
			}

			try {
				// 獲取父級bean定義,合併公共屬性
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				// 獲取bean的依賴,保證其依賴的bean提早被正常的初始化
				String[] dependsOn = mbd.getDependsOn();
				// 若是依賴有其餘bean,就先初始化其依賴的bean
				if (dependsOn != null) {
					// ...
				}

				// 以單例模式建立
				if (mbd.isSingleton()) {
					// ...
				}

				// 以原型模式建立
				else if (mbd.isPrototype()) {
					// ...
				}
				
				// 若是是其餘模式,就用bean定義資源中配置的生命週期範圍(request、session、application等)
				else {
					// ...
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
複製代碼

配合註釋,核心部分分爲如下幾個小部分:

  • 預檢查
  • 前置工做
  • 按指定模式進行實例化

這樣一看好像很簡單,確實如此,若是你僅僅是想了解一個大體的建立過程,接下來的部分能夠略過,直接進入下一部分,若是你想詳細地瞭解整個建立過程,那麼就請跟着我再進一步分析在代碼中省略的部分

查找容器中bean的定義
// 查找容器中是否有指定bean的定義
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// 若是當前容器中不存在bean的定義,且父容器不爲空,就進入父容器中查找
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				String nameToLookup = originalBeanName(name);
				// 若是父容器是AbstractBeanFactory,說明已經到最頂層容器了,
				// 直接調用其doGetBean方法
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				// 若是指定參數,就根據顯式參數查找
				else if (args != null) {
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				// 若是沒有指定參數,就根據指定類型名查找
				else if (requiredType != null) {
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				// 不然就採用默認查找方式
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
複製代碼

查找bean定義的過程其實是一個遞歸的操做,若是子類中不存在bean定義,就從父類中尋找,若是父類不存在,就去父類的父類中尋找,...,直到抵達最頂層的父類

獲取bean的依賴
// 獲取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);
						try {
							// 調用getBean方法建立依賴的bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
複製代碼

這個方法沒什麼好說的,配合註釋應該能很輕鬆地看懂,重點是其中包含一個檢查循環依賴的過程

以單例模式建立bean

接下來就是整個方法的核心了,這裏的三種建立模式大同小異,這裏只講最經典的單例模式,其他建立模式能夠自行查閱

// 以單例模式建立
				if (mbd.isSingleton()) {
					// 建立單例對象
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// 從緩存中刪除單例,同時刪除接收到該bean臨時引用的bean
							destroySingleton(beanName);
							throw ex;
						}
					});
					// 獲取給定的bean的實例
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
複製代碼

整個方法看起來很是清晰,很好理解,無非就是建立單例,而後返回(不理解‘()->{}’這樣的lambda表達式的,能夠參考個人上一篇博文:函數式編程——Java中的lambda表達式

這段代碼雖然短,可是包含了整個方法中核心的內容:建立bean實例,咱們點進createBean方法,這是一個抽象方法,實現部分在AbstractAutowireCapableBeanFactory中,具體源碼以下:

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

		if (logger.isTraceEnabled()) {
			logger.trace("Creating instance of bean '" + beanName + "'");
		}
		RootBeanDefinition mbdToUse = mbd;

		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}

		try {
			mbdToUse.prepareMethodOverrides();
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
					beanName, "Validation of method overrides failed", ex);
		}

		try {
			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 {
			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
			if (logger.isTraceEnabled()) {
				logger.trace("Finished creating instance of bean '" + beanName + "'");
			}
			return beanInstance;
		}
		catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
		}
	}
複製代碼

看起來很是臃腫,爲了便於分析,咱們把日誌和異常都刪掉,再來看:

@Override
	protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
		RootBeanDefinition mbdToUse = mbd;
		
		// 判斷給定的bean是否能夠被實例化(便是否能夠被當前的類加載器加載)
		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
		// 若是不能夠,就委派給其父類進行查找
		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
			mbdToUse = new RootBeanDefinition(mbd);
			mbdToUse.setBeanClass(resolvedClass);
		}
		// 準備覆蓋bean中的方法
		mbdToUse.prepareMethodOverrides();
		
		// 若是設置了初始化先後的處理器,就返回一個代理對象
		Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
		if (bean != null) {
			return bean;
		}
		
		// 建立bean
		Object beanInstance = doCreateBean(beanName, mbdToUse, args);
		return beanInstance;
	}
複製代碼

是否是一會兒就簡單了不少,這也是分析源碼經常使用的方式,能夠更方便地理解程序結構。好了很少說,咱們看這段程序,首先是傳入了三個參數:bean名稱、父類bean,以及參數列表,而後就是一些常規操做,咱們這裏只看核心方法,發現實際這裏並無建立bean的代碼,畢竟連new都沒有,別急,點進doCreateBean方法,接着看:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
			
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			// 移除緩存(單例模式的一種實現方式)中beanName的映射,並返回這個bean
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			// 若是緩存中沒有該bean,就建立該bean的實例
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		// 對bean進行封裝
		final Object bean = instanceWrapper.getWrappedInstance();
		// 獲取bean類型
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// 對後置處理器加同步鎖
		// 容許後置處理器修改合併後bean定義
		synchronized (mbd.postProcessingLock) {
			// 判斷後置處理器是否處理完成,若是沒有就進行【合併bean定義】後的處理操做
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		// 當即將單例緩存起來,以便於依賴對象的循環引用
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			// 讓容器儘早持有對象的引用,以便於依賴對象的循環引用
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// 初始化bean實例,實際觸發依賴的地方
		Object exposedObject = bean;
		try {
			// 用參數填充bean實例
			populateBean(beanName, mbd, instanceWrapper);
			// 初始化bean對象
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
		
		// 父類是單例對象 && 該bean容許循環引用 && 該bean正在建立
		if (earlySingletonExposure) {
			// 獲取已註冊的單例bean
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				// 若是已註冊的bean和正在建立的bean是同一個,則直接返回這個bean
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				// 若是該bean依賴於其餘bean,且不容許在循環依賴的狀況下注入bean
				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()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// 添加bean到工廠中的一次性bean列表中,僅適用於單例模式
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
複製代碼

具體執行流程已經詳細地註釋在代碼中,我也不許備再複述一遍,相信認真看的都能讀懂,咱們這裏關注一個頗有意思的點,能夠發現代碼中有兩個地方涉及了bean的加載:

// ...
			instanceWrapper = createBeanInstance(beanName, mbd, args);
			// ...
			exposedObject = initializeBean(beanName, exposedObject, mbd);
			// ...
複製代碼

先來看createBeanInstance方法,這裏爲了不不少人看不下去,就不打算放源碼了,我簡單地講一下方法的流程:

  • 預檢查
  • 調用instantiateUsingFactoryMethod工廠方法對bean進行實例化
  • 使用自動裝配方法進行實例化 -- 設置同步標記 -- 若是設置了自動裝配屬性,就調用autowireConstructor方法根據參數類型自動匹配構造方法 -- 不然使用默認的無參構造方法
  • 若是沒有設置自動裝配,就使用構造方法進行實例化

確定有人會問,這個方法不是已經實例化對象了嗎,那後面的方法是幹什麼的?別急,咱們直接進入initializeBean方法中,對源碼有興趣的能夠自行查閱,我這裏也是簡要說下流程:

  • 獲取安全管理接口
  • 根據設定的實例化策略來建立對象

咱們能夠發現,在這個方法裏觸發了applyBeanPostProcessorsBeforeInitialization和applyBeanPostProcessorsAfterInitialization兩個方法,從字面意思上也很好理解,就是前置處理器和後置處理器,在這兩個方法之間,調用了invokeInitMethods方法來執行初始化方法

那麼問題來了,initializeBean和createBeanInstance有什麼區別呢,不都是初始化嗎?實際上,真正實例化Java Bean的是createBeanInstance方法,而initializeBean則至關於咱們的自定義初始化操做,同時在其中也會執行一些前置處理和後置處理

createBeanInstance方法執行完,就至關於咱們簡單new出來一個對象而已,可是這個對象沒有添加事務,沒有添加aop,沒有進行url的映射等等操做,因此就須要initializeBean來進行初始化

別忘了,以前咱們說的那個特別長的doGetBean方法還沒完呢,最後還有一段,以下:

// 檢查所需類型是否與bean類型匹配(若是沒有設置檢查類型匹配,最後會進行強制類型轉換)
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, 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, requiredType, bean.getClass());
			}
		}
		return (T) bean;
複製代碼
階段總結

依賴注入階段有點長,咱們這裏作一下總結,總共步驟以下:

  1. 執行getBean,內部調用了doGetBean方法
  2. 檢查緩存,若是緩存中有單例,就直接返回
  3. 查找bean的定義,同時進行類型驗證
  4. 合併父級公有屬性,建立依賴對象
  5. 根據設置的建立模式,選擇建立方法
  6. 執行方法的覆蓋,準備建立bean的實例
  7. 檢查註冊表,若是註冊表中存在,就直接返回
  8. 不然,建立bean的實例
  9. 對單例進行緩存,以便循環依賴使用
  10. 注入依賴屬性
  11. 執行初始化操做,同時會執行先後處理器的方法
  12. 添加bean到工廠中的一次性列表中(僅適用於單例模式)
  13. 進行類型檢查(若是沒有設置類型檢查,最後會進行強制類型轉換)

總結

我習慣把總結寫成要點的形式,由於這種方式比較清晰,因此儘可能習慣一下

  • 相似於ClassPathXmlApplicationContext這種具體的容器,在初始化時會首先將最頂層容器AbstractApplicationContext設置爲資源加載器,而後會設置資源路徑
  • 容器在初始化時,若是設置了refresh參數,則會在每一次初始化時會從新註冊處理器
  • 容器加載資源是經過obtainFreshBeanFactory方法進行加載的,這個方式實際調用了AbstractRefreshableApplicationContext的loadBeanDefinitions方法進行加載
  • getBean方法的實如今AbstractBeanFactory中,內部調用了doGetBean方法(doGetBean方法的執行流程就在上面)
相關文章
相關標籤/搜索