在 Spring IoC 容器的設計中,容器有兩個系列,能夠當作是容器的具體表現形式:spring
BeanFactory 簡單容器:實現了容器的基本功能,典型方法如 getBean、containsBean、isSingleton;設計模式
ApplicationContext 應用上下文:在簡單容器的基礎上,增長上下文的特性。數據結構
解讀: 爲何要設計兩個系列,而不是一個?這就涉及到架構設計的模式了,底層定義核心流程,上層擴展功能實現,高內聚、低耦合。在架構設計中,這樣的分層是頗有必要的,能夠隨時替換掉一個抽象層。架構
Spring 經過定義 BeanDefinition 來管理基於 Spring 的應用中的各類對象以及它們之間的相互依賴關係。BeanDefinition 抽象了咱們對 Bean 的定義,是讓容器起做用的主要數據類型。IoC容器是用來管理對象依賴關係的,BeanDefinition 就是對依賴反轉模式中管理的對象依賴關係的數據抽象,也是容器實現依賴反轉功能的核心數據結構,依賴反轉功能都是圍繞對這個BeanDefinition的處理來完成的。工具
解讀: BeanDefinition 事實上就是 Bean 的定義在運行時的表現。不管是 xml 配置的 Bean,仍是註解定義的 Bean,又或者是自定義掃描進來的 Bean,最終都經過 BeanDefinition 來承載。若是有自定義的 xml 標籤,解析後也是生成 BeanDefinition 註冊到 IOC 中。這樣設計,IOC 只須要關心 BeanDefinition 便可,極大增長了擴展性和靈活性。當咱們 getBean 的時候,若是 Bean 尚未初始化,容器就會找到 BeanDefinition,而後根據 BeanDefinition 初始化 Bean 及其依賴。架構設計
IoC容器的接口設計如圖所示:設計
BeanFactory 定義了基本的 IoC 容器的規範,包括了 getBean 方法。HierarchicalBeanFactory 接口在繼承了 BeanFactory 後,增長了getParentBeanFactory 方法,使 BeanFactory 具有了雙親IoC容器的管理功能。在接下來的 ConfigurableBeanFactory 中,定義了一些對 BeanFactory 的配置功能,好比經過 setParentBeanFactory 方法設置雙親IoC容器,經過 addBeanPostProcessor 方法配置Bean後置處理器。cdn
解讀:xml
能夠看到 BeanFactory 只定義了基本功能,是一個最核心的容器接口定義。在 BeanFactory 的基礎上 Spring 經過繼承逐層擴充容器的能力。理解如此多的工廠接口就是在理解 Spring 的設計模式,正如前面所說,這裏的繼承關係也是架構分層的體現。經過繼承和擴充,在 ConfigurableBeanFactory 中基本完成了 BeanFactory 系列的接口定義。固然了,接口分層後,BeanFactory 的每一層具體實現也是分層的,後面會具體解讀。這裏能夠看到面向接口開發極大提升了擴展性和靈活性。對象
以 ApplicationContext 爲核心的接口系列中,ListableBeanFactory 和HierarchicalBeanFactory 兩個接口鏈接了 BeanFactory 接口定義和ApplicationConext 應用上下文的接口定義。
在 ListableBeanFactory 接口中,細化了許多 BeanFactory 的接口功能,好比定義了getBeanDefinitionNames 接口方法。對於 ApplicationContext 接口,它經過繼承MessageSource、ResourceLoader、ApplicationEventPublisher 接口,在BeanFactory 的基礎上添加了對高級容器特性的支持。
解讀:
ApplicationContext 繼承了 BeanFactory 接口,具備了容器的基本功能,同時根據上下文的特色,也用 ListableBeanFactory 接口作了功能擴展。上下文與容器的主要區別,仍是體如今容器高級特性上,好比 MessageSource 實現了國際化、ResourceLoader 實現了資源加載、ApplicationEventPublisher 實現了事件機制。所以平時工做中使用上下文會多一點,通常不直接使用 BeanFactory 簡單容器。
在 BeanFactory 中,Bean 是經過 FactoryBean 來獲取的。FactoryBean是一個工廠Bean,能夠生成某一個類型 Bean 的實例,它最大的一個做用是:可讓咱們自定義 Bean 的建立過程。可使用轉義符 「&」 獲得 FactoryBean 自己,用來區分經過容器來獲取 FactoryBean 產生的對象和獲取 FactoryBean 自己。
解讀:
FactoryBean 和 BeanFactory,一個是 Factory,也就是 IOC 容器工廠,一個是特點類型的 Bean。全部的 Bean 都是由 BeanFactory 管理。FactoryBean 是一個能產生或者修飾對象生成的工廠 Bean,它的實現與設計模式中的工廠模式和修飾器模式相似。這兩個類型名稱比較接近,不少人容易混淆,只要記住結尾區分便可,一個是工廠,一個是 Bean。
BeanFactory 提供了使用 IoC 容器的規範,在這個基礎上,Spring 還提供了符合這個 IoC 容器接口的一系列容器的實現供開發人員使用,以 XmlBeanFactory 的實現爲例來講明簡單IoC容器的設計原理。
解讀:
這裏的 XmlBeanFactory 是一個基於 XML 的容器實現。從類圖能夠看到,容器的實現也是分層的,每一層接口都有對應的實現,每個實現都只作本身職責範圍內的事情,經過繼承造成了一個多層次的容器結構。若是咱們要定義本身的容器實現,只須要像它同樣按需繼承和實現便可。必定要理解分層的意義,這樣才能設計出更好的實現。
DefaultListableBeanFactory 實際上包含了基本IoC容器所具備的重要功能,在Spring中,其實是把 DefaultListableBeanFactory 做爲一個默認的功能完整的 IoC 容器來使用的。XmlBeanFactory 在繼承了 DefaultListableBeanFactory 容器的功能的同時,增長了新的功能,是一個能夠讀取以 XML 文件方式定義的 BeanDefinition 的IoC容器。
解讀:
在繼承體系中,DefaultListableBeanFactory 實現了容器的重要功能。XmlBeanFactory 解決了 XML 文件的解析,並把解析出來的 Bean 定義註冊到容器中。這就是一個逐層實現的設計,繼承了默認的實現後,只須要根據本身的場景作定製便可,每一層的實現都不算複雜。
在 XmlBeanFactory 中,初始化了一個 XmlBeanDefinitionReader,用來讀取以XML方式定義的 BeanDefinition。而 XML 做爲資源文件,經過 Resource 類來封裝 I/O 操 做。XmlBeanDefinitionReader 初始化後,調用 loadBeanDefinitions 方法從Resource 中載入 BeanDefinition。
解讀:
一個真正完整的容器在啓動階段主要作幾個事情:
找到 Bean 定義,如 xml、註解等,若是是資源文件能夠用 Resource 類來封裝,支持 ClassPath、jar、URL 等;
初始化 Reader 注入 Resource,BeanDefinitionReader 接口定義瞭解析相關的方法,Spring 默認提供了不少實現類;
Reader 解析 BeanDefinition,初始化後註冊到容器中。
以經常使用的 FileSystemXmlApplicationContext 的實現爲例。主要功能已經在AbstractXmlApplicationContext 中實現了,在 FileSystemXmlApplicationContext中,做爲一個具體的應用上下文,只須要實現和它自身設計相關的兩個功能。
若是應用直接使用 FileSystemXmlApplicationContext,對於實例化這個應用上下文的支持,同時啓動IoC容器的 refresh() 過程。這個 refresh() 過程會牽涉 IoC 容器啓動的一系列複雜操做,同時,對於不一樣的容器實現,這些操做都是相似的,所以在基類中將它們封裝好。因此,咱們在FileSystemXml的設計中看到的只是一個簡單的調用。
解讀:
refresh 是上下文的很重要的一個操做。Spring容器的啓動,初始化一些容器啓動必要的資源,BeanFactory 的建立、初始化,Bean 的建立、初始化、註冊、非懶加載,註冊和設置國際化工具類MessageSource,註冊和設置事件,等一系列過程都在這個 refresh 方法裏面進行調用。關於 refresh 的實現原理,後續會有文章解讀,限於篇幅,這裏就不展開了。
FileSystemXmlApplicationContext 是一個從文件系統加載 XML 的上下文實現,所以
設計了從文件系統中加載XML的功能。
解讀:
能夠看到,Spring 內部上下文的實現和繼承關係很是複雜,難以理解。實際上,按照實現分層的思路去理解仍是比較容易的,每一層只實現本身相關的功能。相似或者公用的能力都往下沉澱變爲底層的基礎能力,上層實現只作調用。看源碼的時候,要有全局視野,哪些是公用能力,哪些是本層次定製功能,這樣就會好理解一點。