javascript
Spring IoC 容器的设计与实现原理
上一篇文章講解的是IOC的原理,這一篇文章主要講解Spring IoC 容器的設計與實現原理
?
1.spring的IOC容器
在 Spring IoC 容器的設計中,容器有兩個系列,可以看成是容器的具體表現形式:
-
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 及其依賴。
?
2.springIOC容器的設計
IoC容器的接口設計如圖所示:
?
BeanFactory 定義了基本的 IoC 容器的規范,包括了 getBean 方法。HierarchicalBeanFactory 接口在繼承了 BeanFactory 后,增加了getParentBeanFactory 方法,使 BeanFactory 具備了雙親IoC容器的管理功能。在接下來的 ConfigurableBeanFactory 中,定義了一些對 BeanFactory 的配置功能,比如通過 setParentBeanFactory 方法設置雙親IoC容器,通過 addBeanPostProcessor 方法配置Bean后置處理器。
?
解讀:
可以看到?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 簡單容器。
?
3.FactoryBean
在 BeanFactory 中,Bean 是通過?FactoryBean 來獲取的。FactoryBean是一個工廠Bean,可以生成某一個類型 Bean 的實例,它最大的一個作用是:可以讓我們自定義 Bean 的創建過程。可以使用轉義符 “&” 得到 FactoryBean 本身,用來區分通過容器來獲取 FactoryBean 產生的對象和獲取 FactoryBean 本身。
解讀:
FactoryBean 和 BeanFactory,一個是 Factory,也就是 IOC 容器工廠,一個是特色類型的 Bean。所有的 Bean 都是由 BeanFactory 管理。FactoryBean 是一個能產生或者修飾對象生成的工廠 Bean,它的實現與設計模式中的工廠模式和修飾器模式類似。這兩個類型名稱比較接近,很多人容易混淆,只要記住結尾區分即可,一個是工廠,一個是 Bean。
?
4.BeanFactory容器的設計原理
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,初始化后注冊到容器中。
?
5.ApplicationContext容器的設計原理
以常用的 FileSystemXmlApplicationContext 的實現為例。主要功能已經在AbstractXmlApplicationContext 中實現了,在 FileSystemXmlApplicationContext中,作為一個具體的應用上下文,只需要實現和它自身設計相關的兩個功能。
?
如果應用直接使用 FileSystemXmlApplicationContext,對于實例化這個應用上下文的支持,同時啟動IoC容器的 refresh() 過程。這個 refresh() 過程會牽涉 IoC 容器啟動的一系列復雜操作,同時,對于不同的容器實現,這些操作都是類似的,因此在基類中將它們封裝好。所以,我們在FileSystemXml的設計中看到的只是一個簡單的調用。
?
解讀:
refresh 是上下文的很重要的一個操作。Spring容器的啟動,初始化一些容器啟動必要的資源,BeanFactory 的創建、初始化,Bean 的創建、初始化、注冊、非懶加載,注冊和設置國際化工具類MessageSource,注冊和設置事件,等一系列過程都在這個 refresh 方法里面進行調用。關于?refresh 的實現原理,后續會有文章解讀,限于篇幅,這里就不展開了。
?
FileSystemXmlApplicationContext 是一個從文件系統加載 XML 的上下文實現,因此
設計了從文件系統中加載XML的功能。
?
解讀:
可以看到,Spring 內部上下文的實現和繼承關系非常復雜,難以理解。實際上,按照實現分層的思路去理解還是比較容易的,每一層只實現自己相關的功能。類似或者公用的能力都往下沉淀變為底層的基礎能力,上層實現只做調用。看源碼的時候,要有全局視野,哪些是公用能力,哪些是本層次定制功能,這樣就會好理解一點。
總結
以上是生活随笔為你收集整理的Spring IoC 容器的设计与实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 移动硬盘做pe启动盘
- 下一篇: SpringBoot 3.0最低版本要求