天天看點

spring IOC原理——初始化——定位IOC初始化過程

IOC

IOC設計模式是企業應用開發中,解耦元件之間的複雜關系的利器,Spring IOC子產品就是這個模式的一種實作,Spring IOC提供了一個基本的JAVABean容器,通過IOC模式管理依賴關系,并通過依賴注入和AOP切面增強為JAVABean這樣的POJO對象賦予事務管理、生命周期管理等基本功能。

前言:主要記錄IOC初始化過程的幾個步驟,參考:SPRING技術内幕:深入解析SPRING架構與設計原理,多年前翻過的一本Spring原理書,裡面講的細節大部分都忘了,回溯一下,順便做個記錄,也好将來翻閱,對書中的IOC,AOP,WEB等都做詳細的記錄,此章節為Spring系列,會不斷上傳,篇幅原因,一章就講一部分。先簡單介紹一下IOC的幾個底層接口,以及核心容器,主要講解IOC容器初始化的定位部分

涉及核心接口

Resource

資料源接口,封裝了InputStream,作用是為容器提供使用者資料源的接口。通俗的講,容器啟動需要的配置檔案或配置類在哪?
           

ResourceLoader

加載資源的政策接口
           

BeanDefinition

BeanDefinition是IOC容器體系中非常重要的核心資料結構,可以看成是對bean定義的抽象  
           

BeanDefinitionReader

用于将Resource裝載入BeanDedintion中的解析器
           

BeanFactory

容器基類接口,所有IOC容器的父接口 
           

ApplicationContext

應用上下文容器的父接口
           
spring IOC原理——初始化——定位IOC初始化過程

紅色線路從接口BeanFactory——HierarchicalBeanFactroy——ConfigurableBeanFactory主要設計路徑

以ApplicationContext應用上下文接口為核心的接口設計,主要涉及幾口

BeanFactory——ListableBeanFactory——ApplicationContext——WebApplicationContext / ConfigurableApplicationContext

常用的應用上下文基本上都是WebApplicationContext / ConfigurableApplicationContext實作在這個接口體系中

 ListableBeanFactory和HierarchicalBeanFactory兩個接口,連接配接BeanFactory接口定義和ApplicationContext應用上下文的接口定義。

 ApplicationContext通過繼承MessageSouree、ResourceLoader、ApplicationEvenPublisher接口,在BeanFactory簡單容器的基礎上添加了許多對進階容易的特性支援   
           

IOC初始化過程

定位

Resource定位過程,這裡指的是BeanDefinition的資源定位,它由ResourceLoader通過統一的Resource接口完成,這個Resource對各種形式的BeanDefinition的使用提供了統一接口,如FileSystemResource、ClassPathResource。定位過程類似于容器尋找資料的過程,就像水桶裝水先要找水。

BeanDefinition的Resource定位步驟:

以程式設計的方式使用DefaultListableBeanFactory,先要定義Resource來定位容器使用的BeanDefinition.

ClassPathResource resource=new ClassPathResource("beans.xml"); (找水)建立IOC配置檔案的資源,
 
   DefaultListableBeanFactory factory = new DefaultListableBeanFactory();(桶)建立一個BeanFactory。
 
  (裝水器)建立一個讀取器,resource并不能直接被使用,必須通過BeanDefinitionReader來對這些資訊進行處理。
   XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory); 
 
   reader.loadBeanDefinition(res);(裝水)從定義好的資源位置讀入配置資訊
           

DefaultListableBeanFactory

是接口ConfigurableListableBeanFactory和BeanDefinitionRegistry的預設實作,是一個純粹的容器,需要為它配置特定的讀取器才能完成這些功能,适合用于定制IOC,可以了解為Spring容器中預設的對象工廠的實作,是一個比較全面的對象工廠。工廠中的Bean都是基于中繼資料定義的 bean 和通過post-processors擴充的bean。它的典型作用就是注冊所有的bean通過讀取bean的配置檔案,這樣就可以通過bean的命名友善快速通路bean,通過本地緩存表。

ApplicationContext

一般我們使用ApplicationContext容器,ApplicationContext通過繼承MessageSouree、ResourceLoader、ApplicationEvenPublisher接口,在BeanFactory簡單容器的基礎上添加了許多對進階容易的特性支援,這個接口系統是以BeanFactory和ApplicationContext為核心的,而BeanFactory又是IOC容器的最基本接口,在ApplicationContext的設計中,一方面,可以看到它內建了BeanFactory接口體系中的ListableBeanFactory、autowireCapableBeanFactory\HierarchicalBeanFactory等BeanFactory接口,具備了BeanFactory IOC容器的基本功能,另一方面通過繼承MessageSource\ResourceLoader\ApplicationEventPublisher這些幾口,BeanFactory為ApplicationContext賦予了更進階的IOC容器特性,為了再Web環境中使用它,還涉及了WebApplicationContext接口,而這個接口通過繼承ThemeSource接口來擴充功能

先來看看三個常用的ApplicationContext實作類:

FileSystemXmlApplicationContext:從XML檔案中載入Resource(配置檔案)

ClassPathXmlApplicationContext:從類路徑載入Resource(配置類)

XmlWebApplicationContext:從Web容器載入Resource(web項目)
           

我們主要以FileSystemXmlApplicationContext為例,講述一下IOC容器中ApplicationContext系列的定位過程

先來看看FileSystemXmlApplicationContext的繼承體系

spring IOC原理——初始化——定位IOC初始化過程

FileSystemXmlApplicationContext的具體實作,要走進源碼,篇幅有限,隻貼關鍵代碼

//初始化過程中,調用refresh函數載入BeanDefinition,這個refresh啟動了BeanDefinition的載入過程,它是容器啟動的入口

public FileSystemXmlApplicationContext(

String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)

throws BeansException {

super(parent);

setConfigLocations(configLocations);

if (refresh) {

refresh();

}

}

@Override

protected Resource getResourceByPath(String path) {

if (path.startsWith("/")) {

path = path.substring(1);

}

return new FileSystemResource(path);

}

我們來找找BeanDefinition的完整定位過程,首先檢視調用棧

spring IOC原理——初始化——定位IOC初始化過程

清除看到BeanDefinition資源定位的過程,最初由refresh方法觸發

那麼,FileSystemXmlApplicationContext是在哪裡BeanDefinitionReader的呢?

根據調用棧進入源碼

AbstractApplicationContext——refresh()方法

較長的描述了整個ApplicationContext的初始化過程,BeanFactory更新,MessageSource和PostProcessor注冊,看起來更像是對ApplicationContext進行初始化的模闆或執行提綱,為Bean的生命周期管理提供了條件

spring IOC原理——初始化——定位IOC初始化過程

進入obtainFreshBeanFactory()——調用了模闆方法refreshBeanFactory();該方法由子類去實作,這裡的實作類是 AbstractRefreshableApplicationContext類
           
spring IOC原理——初始化——定位IOC初始化過程

loadBeanDefinitions()方法是AbstractRefreshableApplicationContext類的抽象方法,由子類 AbstractXmlApplicationContext來實作

執行個體化了XmlBeanDefinitionReader

spring IOC原理——初始化——定位IOC初始化過程

具體實作:loadBeanDefinitions(XmlBeanDefinitionReader reader)

spring IOC原理——初始化——定位IOC初始化過程

看到具體的載入過程是委托給BeanDefinitionReader來完成的,因為這裡的BranDefinition是通過XML檔案定義,是以這裡使用XmlBeanDefinitionReader 來載入BeanDefinition到容器中

我們得出部分結論

1: FileSystemXmlApplicationContext通過調用refresh()容器啟動方法 其中實作了BeanDefinition的載入,

2:載入過程由XmlBeanDefinitionReader來完成,由于使用的是XML方式的定義,是以使用的是 XmlBeanDefinitionReader、如果使用了其他的BeanDefinition定義,則需要其他的BeanDefinitionReader實作類來完成

3:容器實際使用的IOC容器是标準容器DefultListableBeanFactory

而Resource載入在BeanDefinitionReader讀入BeanDefinition時實作

進入reader.loadBeanDefinitions(configLocations);

spring IOC原理——初始化——定位IOC初始化過程

loadBeanDefinitions(location)最後會通過resourceLoader.getResources(location)獲得resource

再調用loadBeanDefinitions(resource);

spring IOC原理——初始化——定位IOC初始化過程

其中getResources(location)為抽象方法,使用的類是DefaultResourceLoader()

spring IOC原理——初始化——定位IOC初始化過程

DefaultResourceLoader預設使用ClassPathContextResource來獲得resource

再看看FileSystemXmlApplicationContext的內建路線上層繼承了DefaultResourceLoader,重寫了getResourceByPath(String path)方法,使用FileSystemResource傳回Resource,在參數Resource中封裝了對XML檔案的I/O操作,是以讀取器可以在打開I/O流後得到XML的檔案對象。有了這個檔案對象以後,将其解析為Document對象,再按照Spring的Bean定義規則來對XML的文檔樹進行解析,這個解析交給了BeanDefinitionParserDelegate來完成。

到此,ApplicationContext的resource定位流程就結束了,而後面的解析,注冊,注入将在下一篇中具體講解