1. 程式人生 > >Spring Bean作用域例項

Spring Bean作用域例項

當通過Spring容器建立一個Bean例項時,不僅可以完成Bean例項的例項化,還可以為Bean指定特定的作用域。Spring支援如下5種作用域:

singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個例項

prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean例項

request:對於每次HTTP請求,使用request定義的Bean都將產生一個新例項,即每次HTTP請求將會產生不同的Bean例項。只有在Web應用中使用Spring時,該作用域才有效

session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新例項。同樣只有在Web應用中使用Spring時,該作用域才有效

globalsession:每個全域性的HTTP Session,使用session定義的Bean都將產生一個新例項。典型情況下,僅在使用portlet context的時候有效。同樣只有在Web應用中使用Spring時,該作用域才有效

  其中比較常用的是singleton和prototype兩種作用域。對於singleton作用域的Bean,每次請求該Bean都將獲得相同的例項。容器負責跟蹤Bean例項的狀態,負責維護Bean例項的生命週期行為;如果一個Bean被設定成prototype作用域,程式每次請求該id的Bean,Spring都會新建一個Bean例項,然後返回給程式。在這種情況下,Spring容器僅僅使用new 關鍵字建立Bean例項,一旦建立成功,容器不在跟蹤例項,也不會維護Bean例項的狀態。

  如果不指定Bean的作用域,Spring預設使用singleton作用域。Java在建立Java例項時,需要進行記憶體申請;銷燬例項時,需要完成垃圾回收,這些工作都會導致系統開銷的增加。因此,prototype作用域Bean的建立、銷燬代價比較大。而singleton作用域的Bean例項一旦建立成功,可以重複使用。因此,除非必要,否則儘量避免將Bean被設定成prototype作用域。
 

在Spring中,bean作用域用於確定哪種型別的 bean 例項應該從Spring容器中返回給呼叫者。bean支援的5種範圍域:

  1. 單例 - 每個Spring IoC 容器返回一個bean例項

  2. 原型- 當每次請求時返回一個新的bean例項

  3. 請求 - 返回每個HTTP請求的一個Bean例項

  4. 會話 - 返回每個HTTP會話的一個bean例項

  5. 全域性會話- 返回全域性HTTP會話的一個bean例項

在大多數情況下,可能只處理了 Spring 的核心作用域 - 單例和原型,預設作用域是單例。

注:意味著只有在一個基於web的Spring ApplicationContext情形下有效!

單例VS原型

這裡有一個例子來說明,bean的作用域單例和原型之間的不同:

package com.yiibai.customer.services;

public class CustomerService 
{
	String message;
	
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

1.單例例子

如果 bean 配置檔案中沒有指定 bean 的範圍,預設為單例。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

       <bean id="customerService" 
            class="com.yiibai.customer.services.CustomerService" />
		
</beans>

執行結果:

package com.yiibai.common;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.yiibai.customer.services.CustomerService;

public class App 
{
    public static void main( String[] args )
    {
    	ApplicationContext context = 
    	 new ClassPathXmlApplicationContext(new String[] {"Spring-Customer.xml"});

    	CustomerService custA = (CustomerService)context.getBean("customerService");
    	custA.setMessage("Message by custA");
    	System.out.println("Message : " + custA.getMessage());
    	
    	//retrieve it again
    	CustomerService custB = (CustomerService)context.getBean("customerService");
    	System.out.println("Message : " + custB.getMessage());
    }
}

輸出結果

Message : Message by custA
Message : Message by custA 

由於 bean 的 “CustomerService' 是單例作用域,第二個通過提取”custB“將顯示訊息由 ”custA' 設定,即使它是由一個新的 getBean()方法來提取。在單例中,每個Spring IoC容器只有一個例項,無論多少次呼叫 getBean()方法獲取它,它總是返回同一個例項。

2.原型例子

如果想有一個新的 “CustomerService”bean 例項,每次呼叫它的時候,需要使用原型(prototype)來代替。

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

   <bean id="customerService" class="com.yiibai.customer.services.CustomerService" 
         scope="prototype"/>
		
</beans>

執行-執行

Message : Message by custA
Message : null

在原型作用域,必須為每個 getBean()方法中呼叫返回一個新的例項。

3. Bean作用域註釋

還可以使用註釋來定義 bean 的作用域。

package com.yiibai.customer.services;

import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

@Service
@Scope("prototype")
public class CustomerService 
{
	String message;
	
	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
}

啟用自動元件掃描

<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-2.5.xsd">

       <context:component-scan base-package="com.yiibai.customer" />
		
</beans>

 

scope=“singleton”

 <bean id="helloWorld" class="com.hzyc.springlearn.HelloWorld" scope="singleton" />

scope=“prototype”

 <bean id="helloWorld" class="com.hzyc.springlearn.HelloWorld" scope="prototype" />