spring IOC容器執行個體化Bean的方式有:
singleton 在spring IOC容器中僅存在一個Bean執行個體,Bean以單一實例的方式存在.
prototype 每次從容器中調用Bean時,都返回一個新的執行個體,即每次調用getBean()時,相當於執行new XxxBean()的操作.
request 每次HTTP請求都會建立一個新的Bean,該範圍僅適用於webApplicationContext環境.
session 同一個HTTP session共用一個Bean,不同HTTP session使用不同的Bean,該範圍僅適用於webApplicationContext環境.
globalSession 同一個全域session共用一個Bean,一般用於portlet應用環境,該範圍僅適用於webApplicationContext環境.
在低版本的spring中,由於只有兩個Bean範圍,所以採用singleton="true|false"的配置方式,spring2.0為了向後相容,依舊支援這種配置方式.不過,spring2.0推薦採用新的配置方式:scope="<範圍類型>;"
-------------------------------------------------
singleton範圍
spring以容器的方式提供天然的單一實例模式功能,任何POJO無須編寫特殊的代碼僅通過配置就可以了.
注意:spring將Bean的預設範圍定為singleton.
singleton例:
<bean id="car" class="com.baobaotao.scope.Car" scope="singleton"/>
<bean id="boss1" class="com.baobaotao.scope.Boss">
<property name="car" ref="car"/>
</bean>
Car Bean聲明為singleton(因為預設是singleton,所以可以不顯式指定).
在預設情況下,spring的ApplicationContext容器在啟動時,自動執行個體化所有singleton的Bean並緩衝於容器中.
雖然啟動時會花費一些時間,但帶來兩個好處:首先對Bean提前的執行個體化操作會及早發現一些潛在的配置問題.
其次Bean以緩衝的方式儲存,當運行時使用到該Bean時就無須再執行個體化了,加快了運行效率.如果使用者不希望在容
器啟動時提前執行個體化singleton的Bean,可以通過lazy-init屬性進行控制:
<bean id="boos1" class="com.baobaotao.scope.Boss" lazy-init="true">
<property name="car" ref="car"/>
</bean>
lazy-init="true"的Bean在某些情況下依舊會提前執行個體化:如果該Bean被其它需要提前執行個體化的Bean引用到,
spring也將忽略延遲執行個體化的設定.
-------------------------------------------------
prototype範圍
採用scope="prototype"指定非單一實例範圍Bean,請看:
<bean id="car" class="com.baobaotao.scope.Car" scope="prototype"/>
<bean id="boss1" class="com.baobaotao.scope.Boss">
<property name="car" ref="car"/>
</bean>
<bean id="boss2" class="com.baobaotao.scope.Boss">
<property name="car" ref="car"/>
</bean>
boss1,boss2所引用的都是一個獨立的Car執行個體.
在預設情況下,spring容器在啟動時不執行個體化prototype的Bean.此外,spring容器將prototype的Bean交給調用
者後,就不再管理它的生命週期.
-------------------------------------------------
web應用環境相關的Bean範圍
如果使用者使用spring的webApplicationContext,則可以使用另外3種Bean的範圍:request,session和globalSession.不過
在使用這些範圍之前,首先必須在web容器中進行一些額外的配置,在高版本的web容器中,則可以利用HTTP請求監聽器進行配置:
<web-app>
...
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
...
</web-app>
細心的朋友可能有一個疑問:在介紹webApplicationContext初始化時,我們已經通過ContextLoaderListener將web容器與
spring容器整合,為什麼這裡又要引入一個額外的RequestContextListener以支援Bean的另外3個範圍呢?
在整合spring容器時使用ContextLoaderListener,它實現了ServletContextListener監聽器介面,ServletContextListener
只負責監聽web容器啟動和關閉的事件.而RequestContextListener實現ServletRequestListener監聽器介面,該監聽器監聽
HTTP請求事件,web伺服器接收的每一次請求都會通知該監聽器.
spring容器啟動和關閉操作由web容器的啟動和關閉事件觸發,但如果spring容器中的Bean需要request,session,globalsession
範圍的支援,spring容器本身就必須獲得web容器的HTTP請求事件,以HTTP請求的事件"驅動"Bean範圍的控制邏輯.
request範圍
顧名思義,request範圍的Bean對應一個HTTP請求和生命週期,考慮下面的配置:
<bean name="car" class="com.baobaotao.scope.Car" scope="request"/>
這樣,每次HTTP請求調用到car Bean時,spring容器建立一個新的Car Bean,請求處理完畢後,銷毀這個Bean.
session範圍
假設將以上car的範圍調整為session類型:
<bean name="car" class="com.baobaotao.scope.Car" scope="session"/>
這樣配置後,car Bean的範圍橫跨整個HTTP session,session中所有HTTP請求都共用同一個Car Bean,當HTTP Session結束後,執行個體
才被銷毀.
globalSession範圍
下面的配置片斷將car的範圍設定為了globalSession:
<bean name="loginController" class="com.baobaotao.scope.Car" scope="globalSession"/>
globalSession範圍類似於session範圍,不過僅在portlet的web應用中使用.Portlet規範定義了全域Session概念,它被組成portlet
web應用的所有子portlet共用.如果不在Portlet web應用環境下,globalSession自然等價於session作有域了