spring源碼:bean的加載

spring源碼:bean的加載

測試代碼

//xml配置文件的解析
ClassPathResource resource = new ClassPathResource("spring.xml");
		BeanFactory beanFactory = new XmlBeanFactory(resource);
		//bean的加載,這篇文章就是講解這一句代碼
		MyTestBean myTestBean = (MyTestBean) beanFactory.getBean("myTestBean");
		System.out.println(myTestBean.getTestStr());

跟蹤入口

通過跟蹤AbstractBeanFactory類的getBean(String name);

public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

找到實際加載函數是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;

		//2. 直接從三級緩存(單例對象、單例提前曝光的對象、單例對象工廠)中獲取bean實例
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			//3.返回bean,有時候並不是直接返回實例本身,而是返回指定方法返回的實例
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			// 4. 原型模式的依賴檢查,例如A還未創建完成的時候 因爲B的創建 再次創建A,就會造成循環依賴
			//當isPrototypeCurrentlyInCreation=true時,也就是說當前bean正在創建中,也就時說明存在循環依賴
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//5.如果beanDefinitionMap中也就是所有已經加載的類中不包括beanName則嘗試從parentBeanFactory中查找
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				//  // 如果沒有,查詢父工廠
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// // 執行帶有args參數的getbean方法
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else {
					// 如果沒有參數,執行標準的getbean方法
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
			}
			//如果不僅僅是做類型檢查,那麼需要標記此Bean正在創建之中
			if (!typeCheckOnly) {
				markBeanAsCreated(beanName);
			}

			try {
				// 6.將存儲xml的GernericBeanDefinition轉換爲RootBeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				//如果beanName對應的類是子類的話,則會合並父類的相關屬性
				checkMergedBeanDefinition(mbd, beanName, args);

				// 7. 獲取依賴的Bean
				String[] dependsOn = mbd.getDependsOn();
				//若存在依賴則遞歸實例化依賴的bean
				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);
						}
					}
				}

				//8.針對不同的scope進行bean的創建
				// 創建單例bean
				if (mbd.isSingleton()) {
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							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 {
						//把當前的beanName加入正在創建beanName的集合中,會在第一步判斷
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//把當前的beanName從正在創建beanName的集合中移除
						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;
			}
		}

		// 9.檢查類型,如果不滿足可以進行類型轉換,如果轉換器進行不了這兩種類型的轉換,則拋出異常
		//將bean轉換成requiredType所指定的類型
		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("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

從上面源碼中可以看到,bean的加載主要是這九步。下面就會一步一步的講解這九步。我們可以先不要深究這個方法中的代碼,先從整體瞭解一下這個方法的主題結構。

1. 轉換對應的beanName

實現方法: transformedBeanName(name)
返回值:真實的beanName
方法說明:doGetBean方法傳入的name,可能並不是beanName,也可能是別名或者是FactoryBean,如果是別名alias,則需要找到對應的beanName;如果是FactoryBean,則需要去除name中&符。

2. 從緩存中加載單例

實現方法: getSingleton(beanName);
返回值:beanName對應的單例對象sharedInstance
方法說明:單例在spring同一容器中只會被創建一次,後續直接就從單例緩存中獲取。
下面是該方法源碼:
DefaultSingletonBeanRegistry.java

protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		//1.從單例緩存中獲取實例
		Object singletonObject = this.singletonObjects.get(beanName);
		//isSingletonCurrentlyInCreation判斷此單例是否正在創建
		//檢查這個bean是不是null,並且這個bean正在創建中的bean的map緩存(singletonsCurrentlyInCreation)中
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			//走到這裏證明,bean不在單例緩存中,而且有程序在創建beanName
			//則鎖住單例緩存
			synchronized (this.singletonObjects) {
				// 2.從提前暴光的單例對象緩存中獲取 bean
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					// 都沒有
					// 3.從單例工廠的緩存中找到對應的單例工廠生產提前暴光的單例
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						//生產單例bean
						singletonObject = singletonFactory.getObject();
						//添加提前暴光的單例的緩存中
						this.earlySingletonObjects.put(beanName, singletonObject);
						//移除對應bean工廠
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

代碼 中的註釋已經很詳細了,不在贅述。
值得一說的是,爲什麼要這麼多層緩存?其實是爲了檢測是否涉及循環依賴。
singletonObjects:用於保存BeanName和創建的bean實例,是個Map對象。
singletonFactories:用戶保存beanName和創建bean的工廠,是個Map對象。
earlySingletonObjects:用戶保存beanName和創建的bean實例,與singletonObjects不同的是,這裏面放的bean還在創建中,可以通過getBean()方法獲取到bean,目的是用來檢測循環依賴。

3. bean的實例化

實現方法:getObjectForBeanInstance(sharedInstance, name, beanName, null);
返回值:真正想要返回的bean
方法說明:從緩存中或者createBean()獲取的都是bean的原始狀態,此方法就是對bean進行實例化。需要強調的是,最原始的bean並不一定是我們真正想要的bean。例如,像要factory-method方法返回的bean.

protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// 若name傳遞的是如“&student”(以&爲前綴)
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			//該bean不是FactoryBean,拋出異常
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass());
			}
		}

		// 如果beanInstance不是FactoryBean,是一個普通的Bean,直接返回
		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			//根據beanName從緩存中加載bean,注意此處的beanName是包含‘&’符
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			//到這裏已經明確知道beanInstance是FactoryBean類型了
			// 從工廠中返回bean實例
			FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
			// 判斷已加載的類中是否定義beanname
			if (mbd == null && containsBeanDefinition(beanName)) {
				//如果對應的bean是子bean的話,則合併父類的相關屬性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//是否是用戶生成的:判斷是用戶生成還是應用程序生成
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}
  • getCachedObjectForFactoryBean(beanName); 獲取bean

FactoryBeanRegistrySupport.java

/** FactoryBean 創建的單例對象的緩存: FactoryBean name --> object */
private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
protected Object getCachedObjectForFactoryBean(String beanName) {
		return this.factoryBeanObjectCache.get(beanName);
	}
  • getObjectFromFactoryBean(factory, beanName, !synthetic);真正獲取FactoryBean的bean
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
		if (factory.isSingleton() && containsSingleton(beanName)) {
			synchronized (getSingletonMutex()) {
				// 從緩存中獲取,factoryBeanObjectCache存放<FactoryBean名稱,Object>
				Object object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					// 緩存中獲取不到,從factory中獲取
					object = doGetObjectFromFactoryBean(factory, beanName);
					// 有可能當執行doGetObjectFromFactoryBean函數時,Bean正在創建,所以此時再獲取一下
					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;
							}
							beforeSingletonCreation(beanName);
							try {
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								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;
		}
	}

從上門代碼可以知道主要創建bean實例的代碼在doGetObjectFromFactoryBean(factory, beanName);方法中,我們繼續追蹤到此方法:

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 {
				//getObject()方法在實現FactoryBean接口時實現的
				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);
		}

		// Do not accept a null value for a FactoryBean that's not fully
		// initialized yet: Many FactoryBeans just return null then.
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}

上面這麼多的代碼其實真正邏輯沒有幾行,在doGetObjectFromFactoryBean方法中我們終於看到了factory.getObject();創建FactoryBean實例的代碼。這一邏輯到此也結束了。

4 . 原型模式的依賴檢查

說明:只有在單例情況下才會嘗試解決循環依賴。

5. 檢測parentBeanFactory()父工廠
7. 尋找依賴

說明:因爲bean的初始化過程中很可能用到某些屬性,而這些屬性很可能是動態配置的。所以要先加載依賴的bean.

8.根據不同的scope進行bean的創建

scope的類型:基本作用域(singleton、prototype),Web 作用域(reqeust、session、globalsession),自定義作用域。
說明:從doGetBean()方法中知道對不同的scope,創建bean的邏輯都封裝在createBean()方法中,下面就去看一看這個方法。
這裏太長了,會專門也一篇文章spring源碼:bean的創建

9. 類型轉換

把bean轉換成參數requiredType類型的。

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