spring-bean 全生命週期時序圖

先來一段簡單的代碼

//獲取資源
ClassPathResource resource = new ClassPathResource("spring-core.xml");
//獲取 BeanFactory 
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//根據新建的 BeanFactory 創建一個 BeanDefinitionReader 對象,該 Reader 對象爲資源的解析器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//裝載資源
reader.loadBeanDefinitions(resource);

整個過程分爲四個步驟:資源定位、裝載、解析、註冊
資源定位部分比較簡單,瞭解Resource、ResourceLoader接口以及常用實現類即可

裝載時序圖
從reader.loadBeanDefinitions(resource)開始
在這裏插入圖片描述
1、調用org.springframework.beans.factory.xml#XmlBeanDefinitionReader(資源解析器)的loadBeanDefinitions方法

2、將resource包裝成org.springframework.core.io.support.EncodedResource對象,主要是爲了對 Resource 進行編碼,保證內容讀取的正確性

5、通過encodedResource.getResource().getInputStream()獲取InputStream,再通過new InputSource(inputStream)包裝成org.xml.sax.InputSource對象,方便後續解析xml

8、通過getEntityResolver()獲取org.xml.sax.EntityResolver接口的實現類,該實現類是爲了尋找xml的驗證文件,也就是.dtd 、.xsd文件,Spring對EntityResolver接口的實現類是
org.springframework.beans.factory.xml.BeansDtdResolver
org.springframework.beans.factory.xml.PluggableSchemaResolver

9、獲取驗證模式,主要是爲了保證xml的正確性,以下是根據xml的內容獲取的結果,也可以手動指定

// 禁用驗證模式
public static final int VALIDATION_NONE = XmlValidationModeDetector.VALIDATION_NONE;
// 自動獲取驗證模式
public static final int VALIDATION_AUTO = XmlValidationModeDetector.VALIDATION_AUTO;
// DTD 驗證模式
public static final int VALIDATION_DTD = XmlValidationModeDetector.VALIDATION_DTD;
// XSD 驗證模式
public static final int VALIDATION_XSD = XmlValidationModeDetector.VALIDATION_XSD;

10、通過org.springframework.beans.factory.xml.DefaultDocumentLoader類最終調用jdk的 javax.xml 庫進行解析返回org.w3c.dom.Document接口實現類

至此裝載部分完成,接下來會對document進行解析,生成 BeanDefinition

解析document時序圖
接上一個時序圖,我們先看一下源碼執行的位置

//org.springframework.beans.factory.xml.XmlBeanDefinitionReader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
			throws BeanDefinitionStoreException {

		try {
			//獲取Document實例
			Document doc = doLoadDocument(inputSource, resource);
			//註冊document
			int count = registerBeanDefinitions(doc, resource);
			if (logger.isDebugEnabled()) {
				logger.debug("Loaded " + count + " bean definitions from " + resource);
			}
			return count;
		}
		//...省略無關代碼
	}

上一個時序圖執行到獲取Document實例,接下來通過registerBeanDefinitions方法完成document解析,生成BeanDefinition並且註冊

在這裏插入圖片描述
從上述圖中可以看出,整個過程主要用到了4個類(實際解析過程遠比上圖複雜)

XmlBeanDefinitionReader:
xml資源解析器,主要負責從xml文件中解析出document

XmlReaderContext:
解析過程中的上下文,包含了解析過程中的用到的配置資源、回調事件等

DefaultBeanDefinitionDocumentReader:
document解析類,包含了上下文XmlReaderContextBean和DefinitionParserDelegate,並且最後完成BeanDefinition註冊

DefinitionParserDelegate:
解析document生成BeanDefinition

1、通過反射創建DefaultBeanDefinitionDocumentReader
4、創建上下文XmlReaderContext
8、創建DefinitionParserDelegate
11、初始化DefinitionParserDelegate,解析xml節點,獲取lazyInit、merge、autowire、autowireCandidates、initMethod、destroyMethod等值
12、判斷節點的命名空間是否是默認命名空間(“http://www.springframework.org/schema/beans”),如果是,則調用parseDefaultElement解析

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
		//import
		if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
			importBeanDefinitionResource(ele);
		}
		//alias
		else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
			processAliasRegistration(ele);
		}
		//bean
		else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
			processBeanDefinition(ele, delegate);
		}
		//beans
		else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
			// recurse
			doRegisterBeanDefinitions(ele);
		}
	}

14、如果不是默認命名空間,例如<tx:annotation-driven />,則調用parseCustomElement
在這裏插入圖片描述
最終會尋找META-INF/spring.handlers文件,根據命令空間可以找到相應的處理器進行解析,這裏就是通過TxNamespaceHandler對<tx:annotation-driven />進行解析
在這裏插入圖片描述

因爲篇幅原因,沒有具體展開解析的細節,建議大家主要細看第12步中對bean節點的解析,在這個過程中會生成BeanDefinition,並且完成註冊

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
		// 進行 bean 元素解析。
		// <1> 如果解析成功,則返回 BeanDefinitionHolder 對象。而 BeanDefinitionHolder 爲 name 和 alias 的 BeanDefinition 對象
		// 如果解析失敗,則返回 null 。
		BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
		if (bdHolder != null) {
			// <2> 進行自定義標籤處理
			bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
			try {
				// <3> 進行 BeanDefinition 的註冊
				// Register the final decorated instance.
				BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
			}
			catch (BeanDefinitionStoreException ex) {
				getReaderContext().error("Failed to register bean definition with name '" +
						bdHolder.getBeanName() + "'", ele, ex);
			}
			//<4> 發出響應事件,通知相關的監聽器,已完成該 Bean 標籤的解析。
			// Send registration event.
			getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
		}
	}

到這裏爲止解析和註冊完結,但是這個時候得到的是BeanDefinition對象,裏面只是裝載了生成bean所需的參數和配置,並不是真正的bean

未完待續…接下來會進入bean初始化流程

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