javascript
Spring IoC(二)IoC容器的初始化过程
(一)IoC 容器初始化過(guò)程概述
1.1簡(jiǎn)要概述初始化過(guò)程
IoC 容器的初始化過(guò)程是通過(guò)refresh() 方法來(lái)啟動(dòng)的,這個(gè)方法標(biāo)識(shí)著IoC 容器正式啟動(dòng)。具體來(lái)說(shuō),這個(gè)啟動(dòng)過(guò)程包括:BeanDefinition 的Resource 定位、載入和注冊(cè)三個(gè)基本過(guò)程。
Spring 把這三個(gè)過(guò)程分開,并使用不同的模塊來(lái)完成,通過(guò)這樣的設(shè)計(jì)方式,可以讓用戶更加靈活的對(duì)這三個(gè)過(guò)程進(jìn)行裁剪或擴(kuò)展,從而方便自己定義IoC 容器的初始化過(guò)程。
第一個(gè)過(guò)程是Resource 的定位過(guò)程。這個(gè)Resource 的定位指的是BeanDefinition 的資源定位,它由ResourceLoader 通過(guò)統(tǒng)一的Resource 接口來(lái)完成。對(duì)于BeanDefinition 的存在形式,可以是文件系統(tǒng)中的,通過(guò)FileSystemResource 來(lái)進(jìn)行抽象;類路徑中定義的Bean 信息可以通過(guò)ClassPathResource 來(lái)進(jìn)行抽象。等等。這個(gè)過(guò)程可以理解為IoC 容器尋找數(shù)據(jù)的過(guò)程。
第二個(gè)過(guò)程是BeanDefinition 的載入。這個(gè)載入過(guò)程是把用戶定義好的Bean 定義成IoC 容器內(nèi)部的數(shù)據(jù)結(jié)構(gòu),而這個(gè)容器內(nèi)部數(shù)據(jù)結(jié)構(gòu)就是BeanDefinition。具體來(lái)說(shuō),這個(gè)BeanDefinition 實(shí)際上就是POJO 對(duì)象在IoC 容器中的抽象,通過(guò)這個(gè)BeanDefinition 定義的數(shù)據(jù)結(jié)構(gòu),使IoC 容器能夠方便地管理Bean。
第三個(gè)過(guò)程是向IoC 容器中注冊(cè)這些BeanDefinition 的過(guò)程。這個(gè)過(guò)程是通過(guò)BeanDefinitionRegistry 接口的實(shí)現(xiàn)來(lái)完成的。這個(gè)注冊(cè)過(guò)程把載入過(guò)程中解析得到的BeanDefinition 向IoC 容器進(jìn)行注冊(cè)。在IoC 容器內(nèi)部將BeanDefinition 注入到一個(gè)HashMap 中去,IoC 容器就是通過(guò)這個(gè)HashMap 來(lái)持有這些Bean 數(shù)據(jù)的。
這里談的IoC 容器的初始化過(guò)程,并不包含Bean 依賴注入的實(shí)現(xiàn)。在Spring IoC 的設(shè)計(jì)中,Bean 定義的載入和依賴注入是兩個(gè)獨(dú)立的過(guò)程。依賴注入一般發(fā)生在第一個(gè)通過(guò)getBean() 向容器中獲取Bean 的時(shí)候。但是也并不全是這樣,比如我們對(duì)某個(gè)Bean 設(shè)置了lazyinit 屬性,那么Bean 的依賴注入在其初始化的過(guò)程中就已經(jīng)完成了。
(二)IoC 容器具體初始化過(guò)程解析
2.1BeanDefinition 的Resource 定位
ApplicationContext 是一個(gè)接口,其實(shí)現(xiàn)類主要有:FileSystemXmlApplicationContext、
ClassPathXmlApplicationContext 和XmlWebApplicationContext 等。從這些類的名字就可以分析的出其加載文件的位置。FileSystemXmlApplicationContext 可以從文件系統(tǒng)中載入Resource、ClassPathXmlApplicationContext 可以從類路徑下載入Resource、XmlWebApplicationContext 可以從Web 容器中載入Resource。
這里以FileSystemXmlApplicationContext 為例,來(lái)分析ApplicationContext 的實(shí)現(xiàn)是如何完成Resource 定位的,下面是這個(gè)類對(duì)應(yīng)的繼承體系。
下面是更為詳細(xì)的繼承體系。
從上圖中可以看出FileSystemXmlApplicationContext 已經(jīng)通過(guò)繼承AbstractApplicationContext 具備了ResourceLoader 的功能,因?yàn)锳bstractApplicationContext 繼承自DefaultResourceLoader。下面是其源代碼:
對(duì)BeanDefinition 資源定位的過(guò)程,最初是由refresh() 方法觸發(fā)的,refresh() 方法的調(diào)用是在
FileSystemXmlApplicationContext 的構(gòu)造函數(shù)中啟動(dòng)的。getResourceByPath() 方法的調(diào)用過(guò)程主要如下:
從上面的源代碼中可以看出,只要是以XML 文件方式存在的BeanDefinition 都能夠得到有效的處理。上面的源代碼中并沒(méi)有涉及到BeanDefinition 的信息讀入,那么FileSystemXmlApplicationContext 是怎么完成信息的讀入的呢?
上面已經(jīng)提到過(guò)BeanDefinition 資源的定位、載入和注冊(cè)過(guò)程都是分開進(jìn)行的。關(guān)于這個(gè)讀入器的配置,可以在FileSystemXmlApplicationContext 的基類AbstractRefreshableApplicationContext 中查看。
這里主要看AbstractRefreshableApplicationContext 中的refreshBeanFactory() 方法的實(shí)現(xiàn),
這個(gè)方法被FileSystemXmlApplicationContext 構(gòu)造函數(shù)中的refresh() 方法所調(diào)用。在refreshBeanFactory()這個(gè)方法中,通過(guò)createBeanFactory() 創(chuàng)建一個(gè)IoC 容器供AppliCationContext 使用。這個(gè)IoC 容器就是上一篇博文中提到的DefaultListableBeanFactory。同時(shí),還啟動(dòng)了loadBeanDefinitions() 來(lái)載入BeanDefinition。下面是refreshBeanFactory() 的方法的源碼:
在BeanDefinition 定位完成的基礎(chǔ)上,就可以通過(guò)返回的Resource 對(duì)象來(lái)進(jìn)行BeanDefinition 的載入了。在完成定位過(guò)程后,為BeanDefinition 的載入創(chuàng)造了I/O 操作的條件,但是具體的數(shù)據(jù)還沒(méi)有開始讀入。
2.2BeanDefinition 的載入和解析
先發(fā)出來(lái),慢慢更!
總結(jié)
以上是生活随笔為你收集整理的Spring IoC(二)IoC容器的初始化过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 车险哪些必须买
- 下一篇: 为什么Spring Boot项目引入依赖