上次說到spring IOC 過程當中的幾個重要接口: Resource, BeanDefinition, BeanDefinitionRender ,BeanFactory, ApplicationContext spring
簡單說了spring 的bean初始化流程:由 Resource接口的具體實現定位,讀取資源文件。交給BeanfinintionRender進行bean的解析解析獲得spa
bean的描述對象BeanDefinition 。最後 BeanDefinitionRegister 會將已經等到的bean註冊到 BeanFactory 容器中去完成bean的實例化xml
過程。對象
首先請看一個簡單使用Spring的代碼:blog
不知道有沒有這樣使用過spring呢!這正是上面所說的spring在IOC初始化時的三個步驟。這樣的獲取是否是讓你更明白IOC的初始化脈絡?繼承
咱們能夠將 IOC容器初始化(bean的實例化) 過程分爲 3 個部分 A:資源文件的定位 B:bean的解析,加載 C:bean的"註冊"將解析後的BeanDefinition對象註冊到BeanFactory接口
中去.(該初始化過程是不包涵Bean 的依賴注入的 ,什麼時候完成依賴呢? ) 慢慢往下看吧......資源
步驟1: BeanDefinition 資源文件的定位。get
上次說到spring 中有個重要的接口Resource 該接口負責Spring 資源文件的加載讀取等操做.Reource根據不一樣的文件類型定位BeanDefinition。源碼
還記得FileSystemResource,ClassPathResource這倆個子類嗎?他們都是 Resource 的具體實現。分別讀取不一樣路徑下的資源文件獲取BeanDefinition
查看上面的代碼Spring 經過Resource 來定位BeanDefinition資源文件,而後在使用BeanDefinitionRender來將定位的資源文件處理後獲得Spring要使用的BeanDefinition
對象。由於咱們使用的是單純的容器僅僅是一個能裝載 bean 的容器而已因此對於要使用什麼樣的Resource,什麼樣的BeanDefinitioRender都是由咱們本身說了算的,因此這裏就
很靈活了可是,由於什麼都要本身定製工做量就上來了。
爲何會這麼說?還記得ApplicationContext這個NB的接口嗎?找個具體實現去看看吧爲啥我們在使用spring提供的這個接口的時候不用這寫額外操做呢?由於別人辦理作了呀看
看別人怎麼作的吧!
怎麼樣很簡單吧!!!!
既然他已經獲得了具體的Resource,那麼FileSystemApplicationContext是怎樣進行數據處理的,他是如何初始化BeanDefinition,BeanDefinitionRender的呢?查看該類並無香瓜的代碼,
僅包含多個構造的重載方法,還有這個定位資源文件的方法 getResourceByPath(....);
那麼只有向他的父類找答案了! 在 AbstractRefreshableWebApplicationContext 中找到了答案! 看看FileSystemXmlApplicationContext的繼承關係
查看到AbstractRefreshableWebApplicationContext類的時候發了問題看一下refreshBeanFactory()方法吧!
該方法建立了 DefaultListableBeanFactory beanFactory = createBeanFactory(); 一個IOC 容器用來承載解析的BeanDefinition,容器有了那麼BeanDefinition,和BeanDefinitionRender在哪裏呢 ?
回想一下文章開始的時候建立IOC的代碼 建立好了工廠以後接着作了什麼操做,ok如今是Resource,BeanFactory 接着就該BeanDefinitionRender( factory ) ;,還有他的loadBeanDefinitions(resource);
就能夠完成BeanDefinition的定位,載入了。這裏依然是 loadBeanDefinitions(beanFactory);
是否是和剛纔咱們本身獲取很相近呢? 原來BeanDefinitionRender,BeanDefinition等都是在父類中執行的載入Bean 的操做固然這是合理的由於對於bean的定位來講不一樣的只是文件的路徑也就是path用說不
同而已,那麼具體的路徑交給具體的子類來實現就ok了,由子類本身來肯定使用的資源。
2:BeanDefinition的載入,解析過程
FileSystemXmlApplicationContext.refresh();方法初始化BeanDefinition的入口方法。該方法會調用AbstractRefreshableApplicationContext中的refreshBeanFactory();方法完成 容器的建立 BeanDefinitionRender的初始化BeanDefinition載入等操做
在refreshBeanFactory()方法中會調用 loadBeanDefinitions(beafactory); 該方法由根據不一樣的具體實現調用不一樣。此處調用的是 AbstractXmlApplicationContext中的 loadBeanDefinitions(beafactory);具體實現
最後調用loadBeanDefinitions(XmlBeaDefinitionRender);來載入bean的操做,調用了一系列 loadBeanDefinitions()方法;雖然參數不同可是不注意的話容易出錯,具體解析xml的方法是 XmlBeaDefinitionRender中的doLoadBeanDefinitions(InputSource , Resource ) ;方法完成bean的載入,解析操做。
spring 在什麼時候將解析的bean信息封裝成了本身的 BeanDefinition對象呢?
這是在BeanDefinitionDocumentRender類中執行的經過 proccessBeanDefinitions( Elelment elt , BeanDefinitionParserDelegate delegate );
最終處理beanDefinition是由BeanDefinitionParserDelegate對象來執行的 處理完成後會產生一個BeanDefinitionHolder對象該對象包涵了BeanDefinition信息還有一些額外信息好比別名等信息
具體的標籤解析是調用該類中的 parseBeanDefinitionElement(...) ,parseProppertyElements()....等parse方法進行的xml解析在該類中源碼體現就不細說了。
完成解析後就獲得了DeanDefinitionHolder對象就獲得了BeanDefintion的信息。就此bean的載入就完成了!
3:將已經解析好的BeanDefinition註冊到Ioc容器中去.
這一步就是將上面解析獲得的beanDefinition對象放到一個map中去.此時的beanDefinition已經可使用了可是依賴關係還沒有完成。