書名: Spring快速入門作者名: 崔彥威 盧欣欣 王倩本章字數: 1707字更新時間: 2020-06-29 17:30:40
3.1 IOC容器
在第2章中介紹什么是依賴注入時有提到:依賴注入是組件之間的依賴關系由容器在運行期決定的,即由容器動態地將某個依賴關系注入組件之中。那什么是容器呢?既然Spring框架實現了IOC,那么Spring中的容器是什么呢?
3.1.1 容器介紹
在日常生活中,容器是指用以容納物料并以殼體為主的基本裝置,是用來盛放東西的。在編程中,容器是用來存儲和組織其他對象的對象,首先要確定容器也是對象,也可以當作bean,只是這個對象是用來存儲和組織其他對象的,那其他對象是什么呢?其他對象其實就是bean對象,這也是面向對象編程的一種體現,萬物皆對象。Spring提供了BeanFactory、ApplicationContext兩個IOC容器來管理眾多的bean對象。
3.1.2 BeanFactory
一提到工廠,我們可能就會想到富某康。工廠是一類用以生產貨物的大型工業建筑物。BeanFactory不是用來生產貨物的,而是用來生產管理bean的。BeanFactory會在bean生命周期的各個階段中對bean進行管理,并且Spring將這些階段通過各種接口暴露給我們,讓我們可以對bean進行各種處理。我們只要讓bean實現對應的接口,那么Spring就會在bean的生命周期調用我們實現的接口來處理該bean。這是怎么實現的呢?主要分為以下兩個階段。
1.bean容器的啟動
工廠要生產貨物,首先得把工廠運轉起來。同樣,bean容器要管理bean,也需要先把容器啟動起來,獲取到bean的定義信息之后才能管理。
(1)讀取bean的xml配置文件,然后將xml中每個bean元素分別轉換成BeanDefinition對象。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { private volatile Object beanClass; private String scope = SCOPE_DEFAULT; private boolean abstractFlag = false; private boolean lazyInit = false; private int autowireMode = AUTOWIRE_NO; private int dependencyCheck = DEPENDENCY_CHECK_NONE; private String[] dependsOn; private ConstructorArgumentValues constructorArgumentValues; private MutablePropertyValues propertyValues; private String factoryBeanName; private String factoryMethodName; private String initMethodName; private String destroyMethodName;
BeanClass保存bean的class屬性,scope保存Bean的作用域,abstractFlag保存該bean是否抽象,lazyInit保存是否延遲初始化,autowireMode保存是否自動裝配,dependencyCheck保存是否堅持依賴,dependsOn保存該bean依賴于哪些bean(這些bean必須提取初始化),constructorArgumentValues保存通過構造函數注入的依賴,propertyValues保存通過setter方法注入的依賴,factoryBeanName和factoryMethodName用于factorybean,也就是工廠類型的bean,initMethodName和destroyMethodName分別對應bean的init-method和destroy-method屬性。后面會對這些內容進行詳細介紹。
(2)通過BeanDefinitionRegistry將bean注冊到beanFactory中。
上面獲取到bean的信息之后,是怎么注冊到BeanFactory中的呢?其實是通過BeanDefinitionRegistry將bean注冊到beanFactory中的,因為BeanFactory的實現類需要實現BeanDefinitionRegistry接口。

BeanDefinitionRegistry接口提供了根據beanName注冊對應beanDefinition的方法。在DefaultListableBeanFactory類中實現了該方法,并將beanDefinition保存在了ConcurrentHash-Map中。

另外,Spring還對外暴露了一些接口來對bean初始化,例如BeanFactoryPostProcessor。

我們可以翻譯一下postProcessBeanFactory的注釋信息。postProcessBeanFactory可以修改應用上下文中已經進行standard初始化的beanFactory,此時所有bean的定義信息已經加載完成,但還未實例化,允許覆蓋、新增甚至重新初始化bean信息,一個典型的例子就是屬性覆蓋器PropertyOverrideConfigurer。對于一些參數,可以配置在properties中,而不用配置在Spring的XML配置文件中。
2.bean容器的實例化
上面把bean容器啟動之后,工廠算是運轉起來了,配方(beanDefinition)也已經準備充分,然后就是生產(實例化)、管理貨物(bean)了。實例化bean主要通過反射和CGLIB兩種方式,在bean的實例化過程中,Spring也暴露了一些接口,如表3-1所示。
表3-1 在bean的實例化過程中Spring暴露的一些接口

我們可以通過示例演示一下這幾個接口的使用。
(1)創建Maven project,在pom.xml中引入spring-core、spring-context。

(2)創建bean對象,實現上面列出的接口。

(3)bean配置。

(4)測試。
使用ApplicationContext獲取BeanFactory,再通過getBean方法獲取對應的bean,最后調用destroy方法進行銷毀,從輸出結果可以看到依次調用了BeanNameAware、BeanFactoryAware、InitializingBean、DisposableBean接口。

輸出結果:

3.1.3 ApplicationContext
在上面的示例中,使用ApplicationContext獲取了bean的配置,然后直接將ApplicationContext接口對象賦值給了BeanFactory接口對象,為什么可以賦值呢?其實ApplicationContext接口實現了BeanFactory接口。
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,MessageSource, ApplicationEventPublisher, ResourcePatternResolver
從上面ApplicationContext接口的繼承關系可以看到,它還通過繼承其他接口擴展了BeanFactory的功能。
● MessageSource:為應用提供國際化訪問功能。
● ResourcePattern Resolver:提供資源(如URL和文件系統)的訪問支持。
● ApplicationEventPublisher:引入事件機制,包括啟動事件、關閉事件等,讓容器在上下文中提供了對應用事件的支持。它代表的是一個應用的上下文環境。
BeanFactory主要是面對Spring框架的基礎設施,面對Spring自己。Applicationcontext主要面對于Spring使用的開發者。開發者基本都會使用Applicationcontext,而非BeanFactory,所以在上面實例中使用ApplicationContext獲取BeanFactory接口對象。
上面的ApplicationContext對象是通過ClassPathXmlApplicationContext方法獲取的,還有一種獲取方式,即使用FileSystemXmlApplicationContext方法獲取。
● ClassPathXmlApplicationContext表示從類路徑下加載配置文件。文件路徑默認指的是項目的classpath路徑下,所以不需要寫前綴“classpath:”,如果指向絕對路徑,需要加上“file:”。
new ClassPathXmlApplicationContext(new String[] {"ApplicationContext.xml"});
● FileSystemXmlApplicationContext表示從文件系統中加載配置文件。文件路徑默認指的是項目的根目錄下,若想使用項目的classpath路徑,則需要加上“classpath:”。
new FileSystemXmlApplicationContext(new String[]{"classpath: ApplicationContext.xml"});
- AWS Serverless架構:使用AWS從傳統部署方式向Serverless架構遷移
- C++對象模型詳解
- 愛上micro:bit
- Everyday Data Structures
- 零代碼實戰:企業級應用搭建與案例詳解
- Practical Maya Programming with Python
- 金融商業數據分析:基于Python和SAS
- Mastering Citrix? XenDesktop?
- 寫給所有人的編程思維
- Comprehensive Ruby Programming
- Java EE企業級應用開發教程:Spring+Spring MVC+MyBatis(第2版)
- Vue.js從入門到精通
- HTML5 for Flash Developers
- Mastering Python Data Analysis
- 編程真酷:Scratch3.0游戲創作之旅