第三節 Spring加載bean的過程

前言

通過前面兩節的學習我們已經知道了Spring是如何解析XML與裝載BeanDefinition的;在本章節中我們將繼續學習bean的裝載過程這將會面臨更大的挑戰,bean加載的功能實現遠比bean的解析要複雜得多,不過沒關係,步步深入層層解析終將會有收穫。我們還是以一個例子開始:

BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("application.xml"));
User user = (User)beanFactory.getBean("user");

bean的加載

我們在idea中跟蹤getBean("user")進一步探祕,最後來到了我們想看到的AbstractBeanFactory#doGetBean();所以今天的內容將從此開始,我們先貼出該方法的主要代碼:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
		// 1.提取對應的 beanName
		final String beanName = transformedBeanName(name);
		Object bean;
		/* *
		 *檢査緩存中或者實例工廠中是否有對應的實例
		 *爲什麼首先會使用這段代碼呢,
		 *因爲在創建單例 bean 的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環			依賴,
		 * Spring 創建 bean 的原則是不等 bean 創建完成就會將創建 bean 的 					ObjectFactory 提早曝光
		 *也就是將 ObjectFactory 加入到緩存中,一旦下個 bean 創建時候需要依賴上個 			bean 則直接使用 ObjectFactory
		 */
		// 2.直接嘗試從緩存獲取或者 singletonFactories 中的 ObjectFactory 中獲取
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isDebugEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.debug(".....");
				} else {
					logger.debug(".....");
				}
			}
			// 3.返回對應的實例,有時候存在諸如 BeanFactory 的情況並不是直接返回實例本身而是返回指定方法返回的實例 bean
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		} else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
			// 指定的bean是否正在創建中
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
			// 檢查該工廠中是否存在bean定義
			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			// //如果 beanDefinitionMap 中也就是在所有已經加載的類中不包括 beanName 則嘗試從
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				//parentBeanFactory 中檢測
				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 {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			// 如果不是僅僅做類型檢查則是創建 bean,這裏要進行記錄
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				// 4.將存儲 XML 配置文件的 GernericBeanDefinition 轉換爲 RootBeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				// 如果指定BeanName 是子 Bean 的話同時會合並父類 的相關屬性
				checkMergedBeanDefinition(mbd, beanName, args);
				// Guarantee initialization of beans that the current bean depends on.
				String[] dependsOn = mbd.getDependsOn();
				// 若的 存在依賴則需要遞歸實例化依賴的 bean
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"......'");
						}
						//緩存依賴調用
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						} catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"......", ex);
						}
					}
				}
				// Create bean instance.
				// 5.實例化依賴的 bean  後便可以實例化 mbd
				if (mbd.isSingleton()) {
					// 單例模式的創建
					sharedInstance = getSingleton(beanName, () -> {
						try {
							// 創建bean
							return createBean(beanName, mbd, args);
						} catch (BeansException ex) {
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
					 // 創建 多例的bean
				} 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();
					// 指定的 scope  上實例化bean
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("......");
					}
					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,
								"......",
								ex);
					}
				}
			} catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
		// // 檢査需要的類型是否符合 bean
		// 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.isDebugEnabled()) {
					logger.debug("......", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

我們來總結一下這一段代碼都幹了什麼;

  1. 轉換對應beanName

或許很多人不理解轉換對應beanName是什麼意思,傳入的參數name不就是beanName 嗎?其實不是,這裏傳入的參數可能是別名,也可能是FactoryBean,所以需要進行一系列的 解析,這些解析內容包括如下內容。
去除FactoryBean的修飾符,也就是如果name="&aa"那麼會首先去除&而使name="aa"取指定alias所表示的最終beanName,例如別名A指向名稱爲B的bean則返回B; 若別名A指向別名B,別名B又指向名稱爲C的bean則返回C。

  1. 嘗試從緩存中加載單例
    單例在Spring的同一個容器內只會被創建一次,後續再獲取bean,就直接從單例緩存中獲 取了。當然這裏也只是嘗試加載,首先嚐試從緩存中加載,如果加載不成功則再次嘗試從 singletonFactories中加載。因爲在創建單例bean的時候會存在依賴注入的情況,而在創建依賴 的時候爲了避免循環依賴,在Spring中創建bean的原則是不等bean創建完成就會將創建bean 的ObjectFactory提早曝光加入到緩存中,一旦下一個bean創建時候需要依賴上一個bean則直 接使用ObjectFactory (後面章節會對循環依賴重點講解)。

  2. bean的實例化
    如果從緩存中得到了 bean的原始狀態,則需要對bean進行實例化。這裏有必要強調一下, 緩存中記錄的只是最原始的bean狀態,並不一定是我們最終想要的bean。舉個例子,假如我 們需要對工廠bean進行處理,那麼這裏得到的其實是工廠bean的初始狀態,但是我們真正需 要的是工廠bean中定義的factory-method方法中返回的bean,而getObjectForBeanlnstance就 是完成這個工作的,後續會詳細講解。

  3. 原型模式的依賴檢查

只有在單例情況下才會嘗試解決循環依賴,如果存在A中有B的屬性,B中有A的屬性, 那麼當依賴注入的時候,就會產生當A還未創建完的時候因爲對於B的創建再次返回創建A, 造成循環依賴,也就是情況:isPrototypeCurrentlylnCreation(beanName)判斷 true

  1. 檢測parentBeanFactory

從代碼上看,如果緩存沒有數據的話直接轉到父類工廠上去加載了,這是爲什麼呢?

可能讀者忽略了一個幣要的判斷條件:parentBeanFactory!=null&&IcontainsBean Definition (beanName), parentBeanFactory != null parentBeanFactory如果爲空,則其他一切都是浮雲, 這個沒什麼說的,但是!containsBeanDefinition(beanName)就比較重要了,它是在檢測如果當前 加載的XML配置文件中不包含beanName所對應的配置,就只能到parentBeanFactory去嘗試然後再去遞歸的調用getBean方法。

  1. 將存儲XML配置文件的GernericBeanDefinition轉換爲 RootBeanDefinition

因爲從XML配置文件中讀取到的bean信息是存儲在GernericBeanDefinition中的,但是所 有的bean後續處理都是針對於RootBeanDefinition的,所以這裏需要進行一個轉換,轉換的同時 如果父類bean不爲空的話,則會一併合併父類的屬性。

  1. 尋找依賴

因爲bean的初始化過程中很可能會用到某些屬性,而某些屬性很可能是動態配置的,並 且配置成依賴於其他的bean,那麼這個時候就有必要先加載依賴的bean,所以,在Spring的 加載順尋中,在初始化某一個bean的時候首先會初始化這個bean所對應的依賴。

  1. 針對不同的scope進行bean的創建

我們都知道,在Spring中存在着不同的scope,其中默認的是singleton,但是還有些其他 的配置諸如prototype、request之類的。在這個步驟中,Spring會根據不同的配置進行不同的初 始化策略。

  1. 類型轉換

程序到這裏返回bean後已經基本結束了,通常對該方法的調用參數requiredType是爲空的, 但是可能會存在這樣的情況,返回的bean其實是個String,但是requiredType卻傳入Integer 類型,那麼這時候本步驟就會起作用了,它的功能是將返回的bean轉換爲requiredType所指定 的類型。當然,String轉換爲Integer是最簡單的一種轉換,在Spring中提供了各種各樣的轉換 器,用戶也可以自己擴展轉換器來滿足需求。

經過上面的步驟後bean的加載就結束了,這個時候就可以返回我們所需要的bean 了;接下來我們具體分析一下代碼中的一些核心步驟,請大家留意上述代碼中註釋的編號順序

流程分析

​ 大概熟悉了這個方法所起的作用之後,我們具體分析一下一些核心步驟所做的事情,按照上述代碼中註釋的編號順序,繼續往下看:

  1. 提取對應的 beanName

    transformedBeanName(name)方法主要是確定原始名稱,將別名解析爲規範名稱。比如將factorybean類型的beanname的前綴&替換掉。

  2. 緩存中獲取單例bean

    跟蹤 getSingleton(beanName) 方法我們來到 DefaultSingletonBeanRegistry類中,代碼如下:

    protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    		Object singletonObject = this.singletonObjects.get(beanName);
    		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    			synchronized (this.singletonObjects) {
    				// 當某些方法需要提前初始化的時候則會調用 addSingletonFactory  方法將對應的
    				//ObjectFactory 初始化策略存儲在 singletonFactories
    				singletonObject = this.earlySingletonObjects.get(beanName);
    				if (singletonObject == null && allowEarlyReference) {
    					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
    					if (singletonFactory != null) {
    						//調用預先設定的 get Object 方法 singletonObject = singletonFactory.getObject();
    						singletonObject = singletonFactory.getObject();
    						//記錄在緩存中,earlySingletonObjects 和 singletonFactories 互斥
    						this.earlySingletonObjects.put(beanName, singletonObject);
    						this.singletonFactories.remove(beanName);
    					}
    				}
    			}
    		}
    		return singletonObject;
    	}
    

    ​ 從方法名就可以知道這是獲取單例的bean,單例在Spring的同一個容器內只會被創建一次,後續再獲取bean直接從單例緩存中獲取,當然 這裏也只是嘗試加載,首先嚐試從緩存中加載,然後再次嘗試嘗試從singletonFactories中加載。 因爲在創建單例bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴, Spring創建bean的原則是不等bean創建完成就會將創建bean的ObjectFactory提早曝光加入到 緩存中,一旦下一個bean創建時需要依賴上個bean,則直接使用ObjectFactory

    ​ 這個方法首先嚐試從singletonObjects裏面獲取實例,如果獲取不到再從earlySingletonObjects 裏面獲取,如果還獲取不到,再嘗試從singletonFactories裏面獲取beanName對應的 ObjectFactory,然後調用這個 ObjectFactory 的 getObject 來創建 bean,並放到 earlySingletonObjects 裏面去,並且從singletonFacotories裏面remove掉這個ObjectFactory,而對於後續的所 有內存操作都只爲了循環依賴檢測時候使用,也就是在allowEarlyReference爲true的情況下才 會使用,而它默認就是true。
    這裏涉及用於存儲bean的不同的map簡單解釋如下。

    • singletonObjects:用於保存 BeanName 和創建 bean 實例之間的關係,bean name —> beaninstance
    • singletonFactories:用於保存BeanName和創建bean的工廠之間的關係,bean name ~> ObjectFactory
    • earlySingletonObjects:也是保存BeanName和創建bean實例之間的關係,與 singletonObjects的不同之處在於,當一個單例bean被放到這裏面後,那麼當bean還 在創建過程中,就可以通過getBean方法獲取到了,其目的是用來檢測循環引用。
    • registeredSingletons:用來保存當前所有已註冊的bean。
  3. 從bean的實例中獲取對象

    ​ 跟蹤 getObjectForBeanInstance()方法,我們來到 AbstractBeanFactory類中,代碼如下:

    protected Object getObjectForBeanInstance(
    			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
    		// bean name是不是以 & 開頭
    		if (BeanFactoryUtils.isFactoryDereference(name)) {
    			if (beanInstance instanceof NullBean) {
    				return beanInstance;
    			}
    			if (!(beanInstance instanceof FactoryBean)) {
    				throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
    			}
    		}
    		// 現在我們有了個 bean 的實例,這個實例可能會是正常的 bean 或者是 FactoryBean
    		// 如果是 FactoryBean 我們使用它創建實例,但是如果用戶想要直接獲取工廠實例而不是工廠的
    		// getObject 方法對應的實例那麼傳入的 name 應該加入前綴
    		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
    			return beanInstance;
    		}
    
    		Object object = null;
    		if (mbd == null) {
    			// 嘗試從緩存中加載 bean
    			object = getCachedObjectForFactoryBean(beanName);
    		}
    		if (object == null) {
    			// Return bean instance from factory.
    			// 到這裏已經明確知道 beaninstance 一定是 FactoryBean 類型
    			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
    			// Caches object obtained from FactoryBean if it is a singleton.
    			//containsBeanDefinition 檢測 beanDefinitionMap 中也就是在所有已經加載的類中檢測 是否定義 beanName
    			if (mbd == null && containsBeanDefinition(beanName)) {
    				//將存儲 XML 配置文件的 GernericBeanDefinition 轉換爲 RootBeanDefinition,如果指定 BeanName 是子 Bean 的話同時會合並父類的相關屬性
    				mbd = getMergedLocalBeanDefinition(beanName);
    			}
    			//是否是用戶定義的而不是應用程序本身定義的
    			boolean synthetic = (mbd != null && mbd.isSynthetic());
    			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
    		}
    		return object;
    	}
    

    這個方法中主要確定了bean的類型是不是 FactoryBean 如果是,又委託給 getObjectFromFactoryBean(factory, beanName, !synthetic)方法,繼續深入。進入 FactoryBeanRegistrySupport類中:

    protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    		if (factory.isSingleton() && containsSingleton(beanName)) {
    			synchronized (getSingletonMutex()) {
    				Object object = this.factoryBeanObjectCache.get(beanName);
    				if (object == null) {
    					// 劃重點
    					object = doGetObjectFromFactoryBean(factory, beanName);
    					// Only post-process and store if not put there already during getObject() call above
    					// (e.g. because of circular reference processing triggered by custom getBean calls)
    					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
    					if (alreadyThere != null) {
    						object = alreadyThere;
    					} else {
    						if (shouldPostProcess) {
    							if (isSingletonCurrentlyInCreation(beanName)) {
    								// Temporarily return non-post-processed object, not storing it yet..
    								return object;
    							}
    							// 正在創建的bean放到緩存中
    							beforeSingletonCreation(beanName);
    							try {
    								//Spring獲取bean的規則中有這樣一條 :儘可能保證所有 bean 初始化後都會調用註冊的 的 BeanPostProcessor的 postProcessAfterlnitialization  方法進行處理
    								object = postProcessObjectFromFactoryBean(object, beanName);
    							} catch (Throwable ex) {
    								throw new BeanCreationException(beanName,
    										"Post-processing of FactoryBean's singleton object failed", ex);
    							} finally {
    								//正在創建的bean從緩存中移除
    								afterSingletonCreation(beanName);
    							}
    						}
    						if (containsSingleton(beanName)) {
    							this.factoryBeanObjectCache.put(beanName, object);
    						}
    					}
    				}
    				return object;
    			}
    		} else {
    			Object object = doGetObjectFromFactoryBean(factory, beanName);
    			if (shouldPostProcess) {
    				try {
    					object = postProcessObjectFromFactoryBean(object, beanName);
    				} catch (Throwable ex) {
    					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
    				}
    			}
    			return object;
    		}
    	}
    

    在這個方法中我們還沒有看到想看的代碼不過沒關係,細心的你早已發現這裏麪包含兩個重要的方法;Object object = doGetObjectFromFactoryBean(factory, beanName);以及 object = postProcessObjectFromFactoryBean(object, beanName);第一個很明顯就是委託獲取bean的實現,第二個是bean的後置處理器;後續章節重點分析。

    private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
    			throws BeanCreationException {
    		Object object;
    		try {
    			if (System.getSecurityManager() != null) {
    				AccessControlContext acc = getAccessControlContext();
    				try {
    					object = AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);
    				} catch (PrivilegedActionException pae) {
    					throw pae.getException();
    				}
    			} else {
                    // 劃重點
    				object = factory.getObject();
    			}
    		} catch (FactoryBeanNotInitializedException ex) {
    			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
    		} catch (Throwable ex) {
    			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
    		}
    		......省略
    		}
    		return object;
    	}
    

    終於我們看到了,object = factory.getObject(); 經過一番波折我們知道了factoryBean的bean最終的獲取的對象就是調用它本身的 getObject()實現的。

  4. Definition的轉換

    	//將存儲 XML 配置文件的 GernericBeanDefinition 轉換爲 RootBeanDefinition
    				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
    ---------------------------
    protected RootBeanDefinition getMergedLocalBeanDefinition(String beanName) throws BeansException {
    		// Quick check on the concurrent map first, with minimal locking.
    		RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
    		if (mbd != null) {
    			return mbd;
    		}
    		// beanDefinitionMap 中獲取 beandefination 返回 RootBeanDefinition
    		return getMergedBeanDefinition(beanName, getBeanDefinition(beanName));
    	}
    --------------------------
    public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
        // 重點
    		BeanDefinition bd = this.beanDefinitionMap.get(beanName);
    		if (bd == null) {
    			if (this.logger.isTraceEnabled()) {
    				this.logger.trace("No bean named '" + beanName + "' found in " + this);
    			}
    			throw new NoSuchBeanDefinitionException(beanName);
    		}
    		return bd;
    	}
    
    

    ​ 在這部分代碼中主要是將GernericBeanDefinition 轉換爲 RootBeanDefinition;在第二節解析xml裝配BeanDefinition的時候我們就知道了最初的bean就是GernericBeanDefinition 類型的。而 beanDefinitionMap中的BeanDefinition也是在第二節所說到的,解析好的BeanDefinition所註冊的map對象;這也正好前後一一印證了。

  5. 實例化依賴的 bean

    // 單例模式的創建
    sharedInstance = getSingleton(beanName, () -> {
        try {
            // 創建bean
            return createBean(beanName, mbd, args);
        } catch (BeansException ex) {
            destroySingleton(beanName);
            throw ex;
        }
    });
    

    ​ 之前我們講解了從緩存中獲取單例的過程,那麼,如果緩存中不存在已經加載的單例bean 就需要從頭開始bean的加載過程了,而Spring中使用getSingleton的重載方法實現bean的加 載過程,進一步深入 DefaultSingletonBeanRegistry類中:

    public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    		Assert.notNull(beanName, "Bean name must not be null");
    		synchronized (this.singletonObjects) {
    			//首先檢査對應的 bean 是否已經加載過,因爲 singleton 模式其實就是複用以創建的 bean,
    			Object singletonObject = this.singletonObjects.get(beanName);
    			//如果爲空.則鎖定全局變量並進行處理
    			if (singletonObject == null) {
    				if (this.singletonsCurrentlyInDestruction) {
    					throw new BeanCreationNotAllowedException(beanName,
    							"......");
    				}
    				if (logger.isDebugEnabled()) {
    					logger.debug("......");
    				}
    				// 正在創建的bean 放到緩存中
    				beforeSingletonCreation(beanName);
    				boolean newSingleton = false;
    				boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
    				if (recordSuppressedExceptions) {
    					this.suppressedExceptions = new LinkedHashSet<>();
    				}
    				try {
    					singletonObject = singletonFactory.getObject();
    					newSingleton = true;
    				}
    				catch (IllegalStateException ex) {
    					singletonObject = this.singletonObjects.get(beanName);
    					if (singletonObject == null) {
    						throw ex;
    					}
    				}
    				catch (BeanCreationException ex) {
    					if (recordSuppressedExceptions) {
    						for (Exception suppressedException : this.suppressedExceptions) {
    							ex.addRelatedCause(suppressedException);
    						}
    					}
    					throw ex;
    				}
    				finally {
    					if (recordSuppressedExceptions) {
    						this.suppressedExceptions = null;
    					}
    					// 正在創建的bean從緩存中移除
    					afterSingletonCreation(beanName);
    				}
    				if (newSingleton) {
    					// 將結果記錄至緩存並刪除加載 bean  過程中所記錄的各種輔助狀態
    					addSingleton(beanName, singletonObject);
    				}
    			}
    			return singletonObject;
    		}
    	}
    

    ​ 上述代碼中其實是使用了回調方法,使得程序可以在單例創建的前後做一些準備及處理操 作,而真正的獲取單例bean的方法其實並不是在此方法中實現的,其實現邏輯是在ObectFactoty 類型的實例singletonFactory中實現的,我們也能在代碼中看到返回的對象也正是調用 singletonFactory.getObject()返回的。而這些準備及處理操作包括如下內容。

    • 檢查緩存是否已經加載過。
    • 若沒有加載,則記錄beanName的正在加載狀態。
    • 加載單例前記錄加載狀態。

    我們返回去看一下 singletonFactory對象的創建過程createBean(beanName, mbd, args),進入 AbstractAutowireCapableBeanFactory類,代碼如下:

    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
    			throws BeanCreationException {
    		if (logger.isDebugEnabled()) {
    			logger.debug("......");
    		}
    		RootBeanDefinition mbdToUse = mbd;
    		/**
    		 * 確保此時確實解析了bean類,如果動態解析的類無法存儲在共享的合併bean定義中。
    		 */
    which cannot be stored in the shared merged bean definition.
    		Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
    		if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
    			mbdToUse = new RootBeanDefinition(mbd);
    			mbdToUse.setBeanClass(resolvedClass);
    		}
    		// Prepare method overrides.準備方法替代 對override屬性進行標記及驗證
    		try {
    			mbdToUse.prepareMethodOverrides();
    		} catch (BeanDefinitionValidationException ex) {
    			throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
    					beanName, "Validation of method overrides failed", ex);
    		}
    		try {
    			// 給BeanPostProcessors一個返回代理而不是目標bean實例的機會
    			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 {
    			// 開始創建bean
    			Object beanInstance = doCreateBean(beanName, mbdToUse, args);
    			if (logger.isDebugEnabled()) {
    				logger.debug("Finished creating instance of bean '" + beanName + "'");
    			}
    			return beanInstance;
    		} catch (...) {
                ......
    			}
    	}
    

    從代碼中我們可以總結出函數完成的具體步驟及功能。

    • 根據設置的class屬性或者根據className來解析Class。
    • 對override屬性進行標記及驗證。
    • 應用初始化前的後處理器,解析指定bean是否存在初始化前的短路操作。

​ 創建bean的過程又委託給 doCreateBean(beanName, mbdToUse, args);去實現,那麼接下來我們老規矩,繼續深入 AbstractAutowireCapableBeanFactory類中:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//根據指定 bean 使用對應的策略創建新的實例,如:工廠方法、構造函數自動注入、簡單初始化 instancewrapper
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
                    // bean的後置處理器
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				} catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"......", ex);
				}
				mbd.postProcessed = true;
			}
		}
		// 是否需要提早曝光: 單例& 允許循環依賴& 當前 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");
			}
			// 爲避免後期循環依賴,可以在 bean 初始化完成前將創建實例的 Object Factory 加入工廠
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// 對 bean 進行填充 , 將各個屬性值注入其中,他可能存在依賴於其他bean的屬性 ,則會遞歸初始
			populateBean(beanName, mbd, instanceWrapper);
			// 調用初始化方法,比如 init-method
			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);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			// earlySingletonReference只有在檢測到有循環依賴的情況下才會不爲空
			if (earlySingletonReference != null) {
				// 如果 exposedObject  沒有在初始化方法中被改變,也就是沒有被增強
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				} 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);
						}
					}
					/**
					 * 因爲 bean 創建後其所依賴的 bean —定是已經創建的,
					 * actualDependentBeans 不爲空則表示當前前 bean 創建後其依賴的的 bean 卻沒有沒全部創建完,也就是說存在循環依賴
					 */
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +					StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
										".......");
					}
				}
			}
		}
		// Register bean as disposable.
		try {
			// 根據 scopse 註冊 bean
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		} catch (BeanDefinitionValidationException ex) {
			throw ......;
		}
		return exposedObject;
	}

我們來看一下這個方法的整體思路:

  • 如果是單例則需要首先清除緩存。
  • 實例化 bean,將 BeanDefinition 轉換爲 Bean Wrapper。轉換是一個複雜的過程,但是我們可以嘗試概括大致的功能,如下所示。
    • 如果存在工廠方法則使用工廠方法進行初始化。
    • 一個類有多個構造函數,每個構造函數都有不同的參數,所以需要根據參數鎖定構造 函數並進行初始化。
    • 如果既不存在工廠方法也不存在帶有參數的構造函數,則使用默認的構造函數進行 bean的實例化。
  • MergedBeanDefinitionPostProcessor 的應用。
    bean合併後的處理,Autowired註解正是通過此方法實現諸如類型的預解析。
  • 依賴處理。
    在Spring中會有循環依賴的情況,例如,當A中含有B的屬性,而B中又含有A的屬性 時就會構成一個循環依賴,此時如果A和B都是單例,那麼在Spring中的處理方式就是當創 建B的時候,涉及自動注入A的步驟時,並不是直接去再次創建A,而是通過放入緩存中的 ObjectFactory來創建實例,這樣就解決了循環依賴的問題
  • 屬性填充。將所有屬性填充至bean的實例中。
  • 循環依賴檢査。
    之前有提到過,在Sping中解決循環依賴只對單例有效,而對於prototype的bean, Spring 沒有好的解決辦法,唯一要做的就是拋出異常。在這個步驟裏面會檢測已經加載的bean是否 已經出現了依賴循環,並判斷是否需要拋出異常。
  • 註冊 DisposableBeano
    如果配置了 destroy-method,這裏需要註冊以便於在銷燬時候調用。
  • 完成創建並返回。
    可以看到上面的步驟非常的繁瑣,每一步驟都使用了大量的代碼來完成其功能,最複雜 也是最難以理解的當屬循環依賴的處理,在真正進入doCreateBean前我們有必要先了解下循 環依賴。

6.創建bean的實例
首先我們從 createBeanlnstance 開始:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// Make sure bean class is actually resolved at this point.
		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());
		}
		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}
		// 如果工廠方法不爲空則使用工廠方法初始化策略
		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}
		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);
			}
		}
		// 根據參數解析構造函數
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			// 構造函數自動駐入
			return autowireConstructor(beanName, mbd, ctors, args);
		}
		// 根據不同的實例化策略進行實例化
		return instantiateBean(beanName, mbd);
	}

雖然代碼中實例化的細節非常複雜,但是在createBeanlntance方法中我們還是可以清晰地 看到實例化的邏輯的。

  • 如果在RootBeanDefinition中存在factoryMethodName屬性,或者說在配置文件中配置 了 factory-method,那麼 Spring 會嘗試使用 instantiateUsingFactoiyMethod(beanName, mbd, aigs)方法
  • 解析構造函數並進行構造函數的實例化。因爲一個bean對應的類中可能會有多個構造 函數,而每個構造函數的參數不同,Spring在根據參數及類型去判斷最終會使用哪個構造函數 進行實例化。但是,判斷的過程是個比較消耗性能的步驟,所以釆用緩存機制,如果已經解析過則 不需要重複解析而是直接從RootBeanDefinition中的屬性resolvedConstructorOrFactoryMethod緩存 的值去取,否則需要再次解析,並將解析的結果添加至RootBeanDefinition中的屬性 resolvedConstructorOrFactoryMethod 中。

我們發現創建 BeanWrapper的任務又委託給 instantiateBean(beanName, mbd);來處理,老規矩繼續深入 AbstractAutowireCapableBeanFactory類中:

	protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
								getInstantiationStrategy().instantiate(mbd, beanName, parent),
						getAccessControlContext());
			} else {
				 // 獲取實例化策略
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		} catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}

依然沒有看到我們想看到的類容,繼續深入 SimpleInstantiationStrategy類中:

public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		// 如果有需要覆蓋或者動態替換的方法則當然需要使用 cglib 進行動態代理,因爲可以在創建代理的同時將動態方法織入類中
		// 但是如果沒有需要動態改變得方法,爲了方便直接反射就可以了
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							constructorToUse =	clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass. 必鬚生成CGLIB子類。
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}

​ 程序中,首先判斷如果beanDefinitioikgetMethodOverrides爲空也就是 用戶沒有使用replace或者lookup的配置方法,那麼直接使用反射的方式,簡單快捷,但是如果使 用了這兩個特性,在直接使用反射的方式創建實例就不妥了,因爲需要將這兩個配置提供的功能切進去,所以就必須要使用動態代理的方式將包含兩個特性所對應的邏輯的攔截增強器設置進去, 這樣纔可以保證在調用方法的時候會被相應的攔截器增強,返回值爲包含攔截器的代理實例。至此一個完整的 BeanWrapper就轉配完了;接下來返回 AbstractAutowireCapableBeanFactory類的 doCreateBean()方法中,繼續完成下面的類容:

// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			// 對 bean 進行填充 , 將各個屬性值注入其中,他可能存在依賴於其他bean的屬性 ,則會遞歸初始
			populateBean(beanName, mbd, instanceWrapper);
			// 調用初始化方法,比如 init-method
			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);
			}
		}

populateBean(beanName, mbd, instanceWrapper);完成了對屬性的填充,二而initializeBean(beanName, exposedObject, mbd);的作用就顯而易見了:

protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		} else {
			// bean是否有aware接口的實現
			invokeAwareMethods(beanName, bean);
		}
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			// 調前置處理器
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}
		try {
			// 執行init方法  自定義的 bean 實 實 現 現 InitializingBean 口 接口
			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()) {
			// 調後置處理器
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
}

雖然說此函數的主要目的是進行客戶設定的初始化方法的調用,但是除此之外還有些其他 必要的工作。

  1. 激活Aware方法
    在分析其 前,我們先了解一下Aware的郵 Spring中些Aware相趣口,比如
    BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware x ServletContextAware 等,實 些Aware接口的bean在被初始之後,可以取得一些相對應的資源,例如實現BeanFactoryAware的bean 在初始後,Spring容器將會注入BeanFactory的實例,而實現ApplicationContextAware的bean,在 bean被初始後,將會被注入Applicationcontext的實例等。
  2. 處理器的應用
    BeanPostProcessor相信大家都不陌生,這是Spring中開放式架構中一個必不可少的亮點, 給用戶充足的權限去更改或者擴展Spring,而除了 BeanPostProcessor外還有很多其他的 PostProcessor,當然大部分都是以此爲基礎,繼承自 BeanPostProcessor。BeanPostProcessor 的 使用位置就是這裏,在調用客戶自定義初始化方法前以及調用自定義初始化方法後分別會調用 BeanPostProcessor 的 postProcessBefbrelnitialization 和 postProcessAfterlnitialization 方法,使用 戶可以根據自己的業務需求進行響應的處理。
  3. 激活自定義的init方法
    客戶定製的初始化方法除了我們熟知的使用配置init-method夕卜,還有使自定義的bean實 現InitializingBean接口 ,並在afterPropertiesSet中實現自己的初始化業務邏輯。

至此createBean(beanName, mbd, args);方法中的所有核心步驟都完了。回到AbstractBeanFactory中我們發現同開始我們曾分析的方法一樣又調用一次·bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);不再闡述。最後一個完整的bean已經初始華完畢了。

後語

Spring的加載bean的流程是複雜而又龐大的,我們的分析相對簡陋但是也包含了幾乎所有的核心流程,日積月累中將會有收穫。下一章節我們將繼續分析spring容器的功能擴展

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章