1. scope概論
spring中scope是一個非常關鍵的概念,簡單說就是對象在spring容器(IOC容器)中的生命週期,也可以理解爲對象在spring容器中的創建方式。
2. scope歷史及分類
目前,scope的取值有5種取值:
在Spring 2.0之前,有singleton和prototype兩種;
在Spring 2.0之後,爲支持web應用的ApplicationContext,增強另外三種:request,session和global session類型,它們只實用於web程序,通常是和XmlWebApplicationContext共同使用。
3. 單個scope詳解
3.1 singleton (單一實例)
此取值時表明容器中創建時只存在一個實例,所有引用此bean都是單一實例。如同每個國家都有一個總統,國家的所有人共用此總統,而這個國家就是一個spring容器,總統就是spring創建的類的bean,國家中的人就是其它調用者,總統是一個表明其在spring中的scope爲singleton,也就是單例模型。
此外,singleton類型的bean定義從容器啓動到第一次被請求而實例化開始,只要容器不銷燬或退出,該類型的bean的單一實例就會一直存活,典型單例模式,如同servlet在web容器中的生命週期。
3.2 prototype
spring容器在進行輸出prototype的bean對象時,會每次都重新生成一個新的對象給請求方,雖然這種類型的對象的實例化以及屬性設置等工作都是由容器負責的,但是隻要準備完畢,並且對象實例返回給請求方之後,容器就不在擁有當前對象的引用,請求方需要自己負責當前對象後繼生命週期的管理工作,包括該對象的銷燬。也就是說,容器每次返回請求方該對象的一個新的實例之後,就由這個對象“自生自滅”,最典型的體現就是spring與struts2進行整合時,要把action的scope改爲prototype。
如同分蘋果,將蘋果的bean的scope屬性聲明爲prototype,在每個人領取蘋果的時候,我們都是發一個新的蘋果給他,發完之後,別人愛怎麼喫就怎麼喫,愛什麼時候喫什麼時候喫,但是注意喫完要把蘋果核扔到垃圾箱!對於那些不能共享使用的對象類型,應該將其定義的scope設爲prototype。
3.3 request
再次說明request,session和global session類型只實用於web程序,通常是和XmlWebApplicationContext共同使用。
<bean id ="requestPrecessor" class="...RequestPrecessor" scope="request" />
Spring容器,即XmlWebApplicationContext 會爲每個HTTP請求創建一個全新的RequestPrecessor對象,當請求結束後,該對象的生命週期即告結束,如同java web中request的生命週期。當同時有100個HTTP請求進來的時候,容器會分別針對這10個請求創建10個全新的RequestPrecessor實例,且他們相互之間互不干擾,簡單來講,request可以看做prototype的一種特例,除了場景更加具體之外,語意上差不多。
3.4 session
對於web應用來說,放到session中最普遍的就是用戶的登錄信息,對於這種放到session中的信息,我們可以使用如下形式的制定scope爲session:
<bean id ="userPreferences" class="...UserPreferences" scope="session" />
Spring容器會爲每個獨立的session創建屬於自己的全新的UserPreferences實例,比request scope的bean會存活更長的時間,其他的方面沒區別,如同java web中session的生命週期。
3.5 global session
<bean id ="userPreferences" class="...UserPreferences" scope="globalsession" />
global session只有應用在基於porlet的web應用程序中才有意義,它映射到porlet的global範圍的session,如果普通的servlet的web 應用中使用了這個scope,容器會把它作爲普通的session的scope對待。
4. scope配置
4.1 xml方式
進行bean的配置時,指定scope。
4.2 註解方式
前提爲配置spring爲註解配置。
5.測試singleton 和prototype
沒加@Scope之前,默認是singleton,默認的bean是單實例的。具體測試如下
- 1.新建一個普遍maven項目(非web 項目),新建配置類Cap3MainConfig
@Configuration
public class Cap3MainConfig {
@Bean
public Person person() {
return new Person("王五", 20);
}
}
- 2 編寫測試類,Cap3Test
public class Cap3Test {
@Test
public void test1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Cap3MainConfig.class);
Person person1 = (Person) context.getBean("person");
Person person2 = (Person) context.getBean("person");
System.out.println(person1 == person2);
}
}
執行結果如下:
返回true, 證明取到的是同一個person bean,所以只實例化了一次。
- 3 添加@Scope(“prototype”)配置多例模式
@Configuration
public class Cap3MainConfig {
@Bean
@Scope("prototype")
public Person person() {
return new Person("王五", 20);
}
}
- 4 再次執行測試類,結果如下
證明bean的創建是多實例的。