Spring IoC - 依賴注入 源碼解析

undefined

前言

上一篇文章中,咱們介紹了Spring IoC 的容器初始化過程 - IoC 容器初始化java

本篇文章中,咱們繼續介紹Spring IoC 依賴注入的過程和源碼解讀。面試

仍是如以前同樣,爲你們梳理一下步驟流程,以便於你們能在內心有個大概的脈絡,更容易讀懂源碼,更容易抓住重點。緩存

主要內容:app

  • beanName 解析轉換
  • 手動註冊Bean檢測
  • 雙親容器檢測
  • 依賴初始化(遞歸)
  • ★ 建立singleton 實例
  • 對象實例化
  • 屬性裝配
  • 處理Bean建立以後的各類回調事件
  • ...

源碼解析

上一章最後一節,容器初始化的倒數第二步,finishBeanFactoryInitialization(beanFactory)實例化全部單例,調用了getBean()方法來作singleton bean 的實例化操做。這就是Spring IoC 依賴注入的入口。ide

在開始以前,有一點須要提一下。前面咱們是從容器初始化以後進來的,但實際操做中,咱們有多是在程序普通運行狀況下,用ApplicationContext.getBean()去獲取容器中bean。不要侷限於剛剛的視角中。函數

如今讓咱們開始吧。post

首先看看getBean()學習

源碼位置:AbstractBeanFactory#getBean(String name)ui

@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
複製代碼

doGetBean()

deGetBean()this

  • beanName 解析轉換
  • 檢測 手動註冊Bean
  • 雙親容器檢測
  • 依賴初始化(遞歸)
  • 建立Bean createBean()
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) throws BeansException {
		// 反正就是獲取到真正beanName
        // 處理兩個狀況,1. 將別名轉化成真的beanName;2. 把FactoryBean的前綴"&"給去了
		final String beanName = transformedBeanName(name);
		Object bean;

		// Eagerly check singleton cache for manually registered singletons.
        // 檢測已經註冊的Bean,保證不重複建立
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				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 + "'");
				}
			}
            // 這個方法仍是有點邏輯的
            // 若是目前得到的sharedInstance 不是FactoryBean,那bean就賦值成sharedInstance,直接返回
            // 若是是FactoryBean就返回FactoryBean建立的實例,
            // 這個也是FactoryBean的知識點,我在個人另外一篇文章也講過了,
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// Fail if we're already creating this bean instance:
            // 直接翻譯:建立過了此 beanName 的 prototype 類型的 bean,那麼拋異常
			// We're assumably within a circular reference.
            // 每每是由於陷入了循環引用
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			// Check if bean definition exists in this factory.
            // 檢查下這個BeanDefinition是否存在
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
                // 當前容器沒有這個BeanDefinition,去parent 容器去找
				String nameToLookup = originalBeanName(name);
				if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}

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

			try {
                // 這個 getMergedLocalBeanDefinition 前面講過哦
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

                // 先初始化依賴的全部 Bean,這個很好理解。
                // 注意,這裏的依賴指的是 depends-on 中定義的依賴
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
                            // 這裏循環依賴概念不要紊亂了
                            // 這裏指的是經過 depends-on 定義形成的循環依賴,
                            // 咱們另一種類成員式的循環引用Spring是支持的
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
                        // 註冊依賴關係
                        // 這麼作的緣由是Spring在即將進行bean銷燬的時候會【首先銷燬被依賴的bean】。
                        // 看SpringBean的初始化和銷燬順序就知道了,依賴關係的保存目的就是這個
                        // 依賴關係的保存是經過一個ConcurrentHashMap<String, Set>完成的,key是bean的真實名字。
						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.
                // 若是是 singleton scope 的,建立 singleton 的實例
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
						@Override
						public Object getObject() throws BeansException {
							try {
                                // 建立Bean的詳情,等下拉出來單獨說
								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);
				}

                // 若是是 prototype scope 的,建立 prototype 的實例
				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);
				}

                // 若是不是 singleton 和 prototype 的話,須要委託給相應的實現類來處理
                // 這裏非重點,咱們的重點是singleton的建立
				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, new ObjectFactory<Object>() {
							@Override
							public Object getObject() throws BeansException {
								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 && bean != null && !requiredType.isInstance(bean)) {
			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());
			}
		}
		return (T) bean;
	}
複製代碼

doCreateBean()

步驟概覽:

  1. 開始是單例的話要先清除緩存;
  2. 實例化bean,將BeanDefinition轉換爲BeanWrapper;
  3. 使用MergedBeanDefinitionPostProcessor,Autowired註解就是經過此方法實現類型的預解析;
  4. 解決循環依賴問題;
  5. 填充屬性,將屬性填充到bean實例中;
  6. 註冊DisposableBean;
  7. 建立完成並返回

三個關注點:

  1. createBeanInstance() 實例化
  2. populateBean(); 屬性裝配
  3. initializeBean() 處理Bean初始化以後的各類回調事件
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {

		// Instantiate the bean.
        // 這個BeanWrapper是建立出來持有對象的
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
            // 若是是singleton,先把緩存中的同名bean消除
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		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;

		// Allow post-processors to modify the merged bean definition.
		// 涉及接口:MergedBeanDefinitionPostProcessor
		// 不是關鍵邏輯,不講了
		synchronized (mbd.postProcessingLock) {
			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;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 這裏是爲了解決循環依賴的,先把初步實例化的Bean實例的引用緩存起來,暴露出去,
		// 這個能夠結合別的文章學習,面試題常考,我後面可能也會寫
		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);
				}
			});
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            // 時序圖中的一步,關鍵步驟,屬性裝配,前面的實例只是實例化,沒有裝配屬性
            // 和前面的createBeanInstance同樣會拉出來說,繼續看下去吧
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
                // 還記得 init-method 嗎?還有 InitializingBean 接口?還有 BeanPostProcessor 接口?
         		// 這裏就是處理 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);
			}
		}


		// 這個邏輯分支我一次性說完吧。
		// 若是該beanName對象已經註冊單例模式,則從單例中獲取,並判斷獲取到的bean實例(B)與BeanWrapper中的bean實例(A)是同一個實例,若是是,則返回A或者B,若是不是,則遞歸找出它的依賴bean。
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
             // earlySingletonReference只有在檢測到有循環依賴的狀況下才會不爲空
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
                    // 兩個是同一個引用,bean初始化完成
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(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.");
					}
				}
			}
		}

		// Register bean as disposable.
		// 註冊DisposableBean;
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}

複製代碼

上一步的三個關注點,分開來說。

1. createBeanInstance()

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
		// Make sure bean class is actually resolved at this point.
        // 解析出 Class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

        // 若是工廠方法不爲空,則是用工廠方法初始化
		if (mbd.getFactoryMethodName() != null)  {
            // 相關知識點看另外一篇文章關於FactoryBean的
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
        // 若是不是第一次建立,好比第二次建立 prototype bean。
   		// 這種狀況下,咱們能夠從第一次建立知道,採用無參構造函數,仍是構造函數依賴注入 來完成實例化
        // 因此註釋說叫shortcut
		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);
			}
		}

		// Need to determine the constructor...
        // 判斷是否採用有參構造函數
        // 構造器自動裝配
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// No special handling: simply use no-arg constructor.
        // 使用無參構造器
		return instantiateBean(beanName, mbd);
	}

複製代碼

2. populateBean(); 屬性裝配

入口方法: AbstractAutowireCapableBeanFactory#populateBean

它的做用是: 根據autowire類型進行autowire by nameby type或者是直接進行設置

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
		PropertyValues pvs = mbd.getPropertyValues();

		if (bw == null) {
			if (!pvs.isEmpty()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
        // 這裏看註解是一個擴展點 
        // InstantiationAwareBeanPostProcessor 的實現類能夠在這裏對 bean 進行狀態修改
        // 不是個經常使用的擴展點,這裏不講了
		boolean continueWithPropertyPopulation = true;

		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (BeanPostProcessor bp : getBeanPostProcessors()) {
				if (bp instanceof InstantiationAwareBeanPostProcessor) {
					InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                    // 若是返回 false,表明不須要進行後續的屬性設值,也不須要再通過其餘的 BeanPostProcessor 的處理
					if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
						continueWithPropertyPopulation = false;
						break;
					}
				}
			}
		}

		if (!continueWithPropertyPopulation) {
			return;
		}

		if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

			// Add property values based on autowire by name if applicable.
            // 經過名字找到全部屬性值,若是是 bean 依賴,先初始化依賴的 bean。記錄依賴關係
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}

			// Add property values based on autowire by type if applicable.
            // 經過類型裝配
			if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}

			pvs = newPvs;
		}

		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

		if (hasInstAwareBpps || needsDepCheck) {
			PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			if (hasInstAwareBpps) {
				for (BeanPostProcessor bp : getBeanPostProcessors()) {
					if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        // InstantiationAwareBeanPostProcessor.postProcessPropertyValues方法
                        // 表明能對屬性值進行修改的能力
                        // 其中一個頗有用實現類提一下,AutowiredAnnotationBeanPostProcessor
                        // 對採用@Autowired和@Value設值的就是這個BeanPostProcessor乾的。
                        // 不展開講了,否則要講不完了
						InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
						pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
						if (pvs == null) {
							return;
						}
					}
				}
			}
			if (needsDepCheck) {
				checkDependencies(beanName, mbd, filteredPds, pvs);
			}
		}
		// 這裏纔是設置bean實例的屬性值
		applyPropertyValues(beanName, mbd, bw, pvs);
	}
複製代碼

3. initializeBean() 處理Bean初始化以後的各類回調事件

看這個方法的javadoc 描述

Initialize the given bean instance, applying factory callbacks as well as init methods and bean post processors.

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareMethods(beanName, bean);
					return null;
				}
			}, getAccessControlContext());
		}
		else {
            // 涉及到的回調接口點進去一目瞭然,代碼都是自解釋的
            // BeanNameAware、BeanClassLoaderAware或BeanFactoryAware
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessBeforeInitialization 回調
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
            // init-methods
            // 或者是實現了InitializingBean接口,會調用afterPropertiesSet() 方法
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}
		if (mbd == null || !mbd.isSynthetic()) {
            // BeanPostProcessor 的 postProcessAfterInitialization 回調
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}
複製代碼

你們發現沒有,BeanPostProcessor 的兩個回調都發生在這邊,只不過中間處理了 init-method。這和我原來的認知有點不同了?由於Spring的源碼中代碼的命名不少時候是自解釋的,不少時候我看英文就知道這些方法的意圖,但在這裏,爲何BeanPostProcessor的前置處理方法postProcessBeforeInitialization()也是在屬性設置完成後調用的?

後面查詢了去看英文的解釋,

BeanPostProcessor is used to interact with newly created bean instances before and/or after their initialization method is invoked by the Spring container. You can use BeanPostProcessor to execute custom logic before and/or after bean’s initialization method is invoked by the Spring container.

BeanPostProcessor的意圖就是在初始化方法的先後作定製化操做。仔細想一想好像這個命名也沒毛病。若是真的是在SpringBean實例化以前調用應該叫BeforeInstantiation。源碼中的initialization指的就是上面的invokeInitMethods操做。

結語

以上,就是關於Spring IoC 依賴注入的主要內容。

Spring IoC 容器這裏還有一些其餘的知識點,有關於SpringIoC 特性的。好比,Spring bean的生命週期、FactoryBean、BeanPostProcessor,都是在使用Spring IoC 容器常常遇到的特性。在瞭解了IoC容器的總體運行原理之後,你應該可以對這些特性進行一些分析,將你使用這些特性的方法和源碼結合起來,融會貫通。

至此,Spring IoC關於依賴注入的源碼「大體」解讀完畢,仍是那句話,上面的源碼解析,確定不會是完備的,只是提取了我認爲重要的東西。

若有疏漏,敬請諒解和本身查閱相關資料學習。若是錯誤,敬請指正!

本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索