Spring中Bean的單例和多例簡單總結
在Spring中,有兩個類型,一個是單例一個和多例,一個Bean同學,要麼是單例要麼是多例。
prototype(多例)和singleton(單例)
在Spring中,bean的Scope常被定義的兩種模式:prototype(多例)和singleton(單例)。
singleton(單例):只有一個共享的實例存在,所有對這個bean的請求都會返回這個唯一的實例。
此取值時表明容器中創建時只存在一個實例,所有引用此bean都是單一實例。如同每個國家都有一個總統,國家的所有人共用此總統,而這個國家就是一個spring容器,總統就是spring創建的類的bean,國家中的人就是其它調用者,總統是一個表明其在spring中的scope爲singleton,也就是單例模型。
此外,singleton類型的bean定義從容器啓動到第一次被請求而實例化開始,只要容器不銷燬或退出,該類型的bean的單一實例就會一直存活,典型單例模式,如同servlet在web容器中的生命週期。
prototype(多例):對這個bean的每次請求都會創建一個新的bean實例,類似於new。
spring容器在進行輸出prototype的bean對象時,會每次都重新生成一個新的對象給請求方,雖然這種類型的對象的實例化以及屬性設置等工作都是由容器負責的,但是隻要準備完畢,並且對象實例返回給請求方之後,容器就不在擁有當前對象的引用,請求方需要自己負責當前對象後繼生命週期的管理工作,包括該對象的銷燬。也就是說,容器每次返回請求方該對象的一個新的實例之後,就由這個對象“自生自滅”。
如同分蘋果,將蘋果的bean的scope屬性聲明爲prototype,在每個人領取蘋果的時候,我們都是發一個新的蘋果給他,發完之後,別人愛怎麼吃就怎麼吃,愛什麼時候吃什麼時候吃,但是注意吃完要把蘋果核扔到垃圾箱!對於那些不能共享使用的對象類型,應該將其定義的scope設爲prototype。
再次強調:Spring bean 默認是單例模式。
在Spring中 使用註解 @Scope進行標識一個Bean範圍。其中@Scope的源碼如下:
public @interface Scope {
/** * scopeName的別名 */
@AliasFor("scopeName")
String value() default "";
/**
* 默認 SCOPE_SINGLETON
* @since 4.2
* 四種類型可以選擇:
* ConfigurableBeanFactory#SCOPE_PROTOTYPE :prototype
* ConfigurableBeanFactory#SCOPE_SINGLETON :singleton
* org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST :request
* org.springframework.web.context.WebApplicationContext#SCOPE_SESSION :
*/
@AliasFor("value")
String scopeName() default "";
/**
* 指定組件是否應配置爲作用域代理,如果是,則該代理應基於接口還是基於子類。
* 默認爲ScopedProxyMode。缺省值,它通常指示,除非在組件掃描指令級別配置了不同的缺省值,否則不應該創
* 建任何作用域代理。
* 類似於Spring XML中的支持 <aop:scoped-proxy/>
*/
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
其中還有 request 和 session,感興趣的朋友可以自行進行了解。
爲什麼用單例或者多例?何時用?
之所以用單例,是因爲沒必要每個請求都新建一個對象,這樣子既浪費CPU又浪費內存;
之所以用多例,是爲了防止併發問題;即一個請求改變了對象的狀態,此時對象又處理另一個請求,而之前請求對對象狀態的改變導致了對象對另一個請求做了錯誤的處理;
當對象含有可改變的狀態時(更精確的說就是在實際應用中該狀態會改變),則多例,否則單例。
如何在單例bean中注入一個多例bean
使用xml放設置Scope
使用註解方式設置Scope