Spring 生命周期與作用范圍
1. 前言
? 上一節(jié),我們多學習了一種初始化 Spring 容器的方式,那么不管是何種初始化容器的方式,目的都是對容器中的 bean 實例做管理的。
本節(jié)我們就學習 Spring 的容器如何管理對象的實例的。主要在于兩個方向:
- 對象的生命周期
- 對象的作用范圍
2. 對象的生命周期
2.1. 生命周期的概念
? 生命周期,通俗的理解就是從出生到死亡的過程,那么對于對象而言,就是實例在 Spring 容器中創(chuàng)建到銷毀的過程。
2.2 生命周期流程概要
簡單地來說,一個 Bean 的生命周期分為四個階段:
(1) 實例化(Instantiation)
(2) 屬性設置(populate)
(3) 初始化(Initialization)
(4) 銷毀(Destruction)
流程圖如下:
Spring 中 bean 的實例化過程:
Bean 實例生命周期的執(zhí)行過程如下:
-
Spring 對 bean 進行實例化,默認 bean 是單例;
-
Spring 對 bean 進行依賴注入;
-
如果 bean 實現(xiàn)了
BeanNameAware
接口,Spring 將 bean 的 id 傳給setBeanName()
方法; -
如果 bean 實現(xiàn)了
BeanFactoryAware
接口,Spring 將調用setBeanFactory
方法,將 BeanFactory 實例傳進來; -
如果 bean 實現(xiàn)了
ApplicationContextAware
接口,它的setApplicationContext()
方法將被調用,將應用上下文的引用傳入到 bean 中; -
如果 bean 實現(xiàn)了
BeanPostProcessor
接口,它的postProcessBeforeInitialization
方法將被調用; -
如果 bean 實現(xiàn)了
InitializingBean
接口,Spring 將調用它的afterPropertiesSet
接口方法,類似地如果 bean 使用了 init-method 屬性聲明了初始化方法,該方法也會被調用; -
如果 bean 實現(xiàn)了
BeanPostProcessor
接口,它的postProcessAfterInitialization
接口方法將被調用; -
此時 bean 已經準備就緒,可以被應用程序使用了,他們將一直駐留在應用上下文中,直到該應用上下文被銷毀;
-
若 bean 實現(xiàn)了
DisposableBean
接口,Spring 將調用它的distroy()
接口方法。同樣地,如果 bean 使用了 destroy-method 屬性聲明了銷毀方法,則該方法被調用;
3. 對象的作用范圍
3.1 介紹
作用范圍四個字很好理解,其實就是對象起作用的范圍在哪,那么到底有哪些作用范圍呢?
3.2 作用范圍舉例
singleton — 單例模式
prototype — 原型模式
request — 請求范圍
session — 會話范圍
application — 應用范圍
3.3 作用范圍詳解
單例模式
單例大家都不陌生,Java 基礎我們學過如何創(chuàng)建單例,而在 Spring 的容器中,bean 的作用范圍如果是 singleton,那么表示容器中僅管理一個共享實例,該單個實例存儲在 Spring 容器的緩存 map 集合中,所有的對象對于該實例的引用,都是從緩存的 map 中返回該對象的實例。
結構圖如下:
圖片解釋:可以看到左側的三個,是通過 bean 標簽實例化的類,而在每個類中都有個 property 引入 accountDao 的依賴,右側表示在內存中僅存在一個 dao 的實例,
這也是默認的實例模式 —— 單例模式。
原型模式
原型模式 聽起來比較模糊,解釋的意思就是 —— 如果 bean 的作用范圍如果是 prototype,那么表示 Spring 容器針對當前對象獲取實例的時候,每次都會重新 new 一個對象,返回給調用者。
結構圖如下:
圖片解釋:可以看到左側的三個,是通過 bean 標簽實例化的類,在每個類中都有個 property 引入 accountDao 的依賴。
右側存在一個 dao 的 bean 標簽配置。而在配置的屬性中,有一個 scope =prototype ,即是原型模式的作用范圍。 每個類中已引入的依賴,Spring 的容器都是通過 class 重新 new 一個實例分別返回給調用者。
其余模式
request
,session
,application
,等等作用范圍工作使用中并不常見,這里不做描述。大家可自行查詢資料。
4. 小結
Spring 的容器中初始化的實例,可以存在多種作用范圍,而最常用的就是 默認的單例模式,至于 prototype 原型也有使用場景。
那么到底是單例模式,還是原型模式都是根據實際需求來決定,如果使用的實例中存在多種共享屬性,又要求數據狀態(tài)不被改變,
那么就必須是原型 prototype 模式,否則使用單例更好。