spring——bean的創建過程
阿新 • • 發佈:2017-10-31
函數參數 oca 復雜 date 析構 require ams decorate custom
- spring的核心容器包括:core、beans、context、express language四個模塊。所以對於一個簡單的spring工程,最基本的就是依賴以下三個jar包即可:
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>4.3.8.RELEASE</version> </dependency
暫時先不考慮express language模塊。
- 通過xml文件創建一個spring bean的大概過程
- 主要考慮以下情況:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
註:beanFactoryTest.xml指上述xml文件;chapter02.MyTestBean是一個簡單的bean(包含一個私有屬性,get,set方法)
- 關於new ClassPathResource("beanFactoryTest.xml")
- 接口InputStreamSource封裝任何能返回InputStream的類。它只有一個方法定義:getInputStream();該方法返回一個InputStream對象。
- Resource接口繼承了InputStreamSource接口
- ClassPathResource類是Resource接口的一個實現類
- 關於new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"))
- 首先對傳入的resource參數做封裝
- 其次通過SAX讀取XML文件的方式來準備InputSource對象
- 最後將準備好的數據通過參數傳入真正的核心處理部分:doLoadBeanDefinitions
- 對於真正的核心處理部分:doLoadBeanDefinitions
- 獲取對XML文件的驗證模式:DTD、XSD
- 加載XML文件,並得到對應的Document。通過SAX解析XML文檔的步驟如下:
- 首先創建DocumentBuilderFactory
- 通過DocumentBuilderFactory創建DocumentBuilder
- 使用DocumentBuilder解析InputSource來返回Document對象
- 根據返回的Document註冊Bean信息
- BeanDefinitionDocumentReader接口的實現類DefaultBeanDefinitionDocumentReader會獲取到document對象的root節點
- 通過root節點獲取所有的bean節點:一種是默認的bean節點:使用parseDefaultElement();方法進行處理;一種是自定義的bean節點:使用delegate.parseCustomElement()方法進行處理,其中delegate是根據自定義節點的命名空間獲取到的自定義的節點處理器;以下只討論對於第一種情況即:對於默認的bean節點的處理。
- 對於默認的bean節點有四種標簽:import、alias、bean、beans,我們這裏主要討論最常用也最復雜的bean標簽:
- 首先委托BeanDefinitionDelegate類的parseBeanDefinitionElement();方法進行元素解析,返回BeanDefinitionHolder類型的實例bdHolder
- 提取元素中的id以及name屬性
- 進一步解析其他所有屬性以及子元素,並統一封裝至GenericBeanDefinition類型的實例中;註:BeanDefinition存在三個實現類:RootBeanDefinition(父節點)、ChildBeanDefinition(子節點)、GenericBeanDefinition(Xml屬性對應的java容器)
- 解析各種屬性:scope屬性、singleton屬性、abstract屬性、lazy-init屬性、autowire屬性、dependency-check屬性、depends-on屬性、autowire-candidate屬性、primary屬性、init-method屬性、destory-method屬性、factory-method屬性、factory-bean屬性
- 解析各種子元素:
- 解析元數據:parseMetaElements
- 解析lookup-method子元素:parseLookupOverrideSubElements
- 解析replaced-method子元素:parseReplacedMethodSubElements
- 解析構造函數參數:parseConstructorArgElements
- 解析property子元素:parsePropertyElements
- 解析qualifier子元素:parseQualifierElements
- 如果檢測到bean沒有指定beanName,那麽使用默認規則為此bean生產beanName
- 將獲取到的信息封裝到BeanDefinitionHolder的實例中
- 當返回的bdHolder下存在自定義屬性時,還需要對自定義標簽進行解析。例如以下包含mybean:user自定義屬性時:
<bean id="test" class="test.Myclass"> <mybean:user username="aaa"/> </bean>
需要用到delegate.decorateBeanDefinitionIfRequired();進行自定義標簽的處理,處理過程如下:
- 遍歷所有的屬性以及所有的子元素
- 根據節點獲取標簽的命名空間
- 根據命名空間判斷是否是默認標簽,這裏只對非默認標簽進行處理,因為對於默認標簽在之前已經處理過了
- 根據命名空間找到對應的處理器
- 使用相應的處理器進行修飾處理
- 對解析完成後的bdHolder進行註冊:包括通過beanName的註冊以及alias(別名)的註冊
- 通過beanName註冊BeanDefinition:this.beanDefinitionMap.put(beanName, beanDefinition)
- 對AbstractBeanDefinition的methodOvirrides屬性進行校驗
- 如果beanName已經註冊過:如果用戶設置了不允許重復註冊,則拋異常,否則直接覆蓋,重新註冊
- 加入beanDfinitionMap
- 清除解析之前留下的對應beanName的緩存
- 通過alias(別名)註冊BeanDefinition:this.aliasMap.put(alias, name);
- alias與beanName相同,則不需要處理,並刪除掉原有alias
- 若aliasName存在,根據用戶是否允許別名覆蓋進行相應的處理
- alias循環檢查。例如:當存在A(key)-->B(value)時,如果還存在B(key)-->A(value)或者B(key)-->C(value)、C(key)-->A(value)時,稱為出現了循環。此時則會拋出異常
- 註冊alias:this.aliasMap.put(alias, name);
- 通過beanName註冊BeanDefinition:this.beanDefinitionMap.put(beanName, beanDefinition)
- 最後發出響應事件,通知相關的監聽器
- 首先委托BeanDefinitionDelegate類的parseBeanDefinitionElement();方法進行元素解析,返回BeanDefinitionHolder類型的實例bdHolder
- 主要考慮以下情況:
spring——bean的創建過程