Spring Framework支持五種作用域(其中有三種只能用在基於web的SpringApplicationContext)。
在每個Spring IoC容器中一個bean定義對應一個對象實例。 |
|
一個bean定義對應多個對象實例。 |
|
在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
|
在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
|
在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於web的Spring ApplicationContext情形下有效。 |
1.Singleton作用域
當一個bean的作用域爲singleton, 那麼Spring IoC容器中只會存在一個共享的bean實例,並且所有對bean的請求,只要id與該bean定義相匹配,則只會返回bean的同一實例。
換言之,當把一個bean定義設置爲singlton作用域時,Spring IoC容器只會創建該bean定義的唯一實例。這個單一實例會被存儲到單例緩存(singleton cache)中,並且所有針對該bean的後續請求和引用都將返回被緩存的對象實例。
Singleton作用域是Spring中的缺省作用域。即默認值!!!
<pre name="code" class="html"><bean id="role" class="spring.chapter2.maryGame.Role" scope="singleton"/>
或者
<bean id="role" class="spring.chapter2.maryGame.Role" singleton="true"/>
2.Prototype
Prototype作用域的bean會導致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調用容器的getBean()方法)時都會創建一個新的bean實例。根據經驗,對所有有狀態的bean應該使用prototype作用域,而對無狀態的bean則應該使用singleton作用域。
請注意,典型情況下,DAO不會被配置成prototype,因爲一個典型的DAO不會持有任何會話狀態,因此應該使用singleton作用域。
對於prototype作用域的bean,有一點非常重要,那就是Spring不能對一個prototype bean的整個生命週期負責:容器在初始化、配置、裝飾或者是裝配完一個prototype實例後,將它交給客戶端,隨後就對該prototype實例不聞不問了。不管何種作用域,容器都會調用所有對象的初始化生命週期回調方法,而對prototype而言,任何配置好的析構生命週期回調方法都將不會被調用。清除prototype作用域的對象並釋放任何prototype bean所持有的昂貴資源,都是客戶端代碼的職責。(讓Spring容器釋放被singleton作用域bean佔用資源的一種可行方式是,通過使用bean的後置處理器,該處理器持有要被清除的bean的引用。)
談及prototype作用域的bean時,在某些方面你可以將Spring容器的角色看作是Java new操作符的替代者。任何遲於該時間點的生命週期事宜都得交由客戶端來處理。在Section 3.5.1, “Lifecycle接口”一節中會進一步講述Spring IoC容器中的bean生命週期。
向後兼容性:在XML中指定生命週期作用域 |
|
如果你在bean定義文件中引用'spring-beans.dtd' DTD,要顯式說明bean的生命週期作用域你必須使用"singleton"屬性(記住singleton生命週期作用域是默認的)。 如果引用的是'spring-beans-2.0.dtd' DTD或者是Spring 2.0 XSD schema,那麼需要使用"scope"屬性(因爲"singleton"屬性被刪除了,新的DTD和XSD文件使用"scope"屬性)。 簡單地說,如果你用"singleton"屬性那麼就必須在那個文件裏引用'spring-beans.dtd' DTD。 如果你用"scope"屬性那麼必須 在那個文件裏引用'spring-beans-2.0.dtd' DTD 或'spring-beans-2.0.xsd' XSD。 |
配置實例:
<bean id="role" class="spring.chapter2.maryGame.Role" scope="prototype"/>
或者
<beanid="role" class="spring.chapter2.maryGame.Role" singleton="false"/>
3. 其他作用域
其他作用域,即request、session以及global session僅在基於web的應用中使用(不必關心你所採用的是什麼web應用框架)。
|
Note |
下面介紹的作用域僅僅在使用基於web的Spring ApplicationContext實現(如XmlWebApplicationContext)時有用。如果在普通的Spring IoC容器中,比如像XmlBeanFactory或ClassPathXmlApplicationContext,嘗試使用這些作用域,你將會得到一個IllegalStateException異常(未知的bean作用域)。 |
3.1. 初始化web配置
要使用request、session和 global session作用域的bean(即具有web作用域的bean),在開始設置bean定義之前,還要做少量的初始配置。請注意,假如你只想要“常規的”作用域,也就是singleton和prototype,就不需要這一額外的設置。
在目前的情況下,根據你的特定servlet環境,有多種方法來完成這一初始設置。如果你使用的是Servlet 2.4及以上的web容器,那麼你僅需要在web應用的XML聲明文件web.xml中增加下述ContextListener即可
org.springframework.web.context.request.RequestContextListener
即:
web-app>
...
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
...
</web-app>
如果你用的是早期版本的web容器(Servlet 2.4以前),那麼你要使用一個javax.servlet.Filter的實現。請看下面的web.xml配置片段:
requestContextFilter
org.springframework.web.filter.RequestContextFilter
requestContextFilter
/*
即:
<web-app>
..
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
...
</web-app>
3.2. Request作用域
考慮下面bean定義:
針對每次HTTP請求,Spring容器會根據loginAction bean定義創建一個全新的LoginAction bean實例,且該loginAction bean實例僅在當前HTTP request內有效,因此可以根據需要放心的更改所建實例的內部狀態,而其他請求中根據loginAction bean定義創建的實例,將不會看到這些特定於某個請求的狀態變化。當處理請求結束,request作用域的bean實例將被銷燬。
<bean id="role" class="spring.chapter2.maryGame.Role" scope="request"/>
3.3. Session作用域
考慮下面bean定義:
針對某個HTTP Session,Spring容器會根據userPreferences bean定義創建一個全新的userPreferences bean實例,且該userPreferences bean僅在當前HTTP Session內有效。與request作用域一樣,你可以根據需要放心的更改所創建實例的內部狀態,而別的HTTP Session中根據userPreferences創建的實例,將不會看到這些特定於某個HTTP Session的狀態變化。當HTTP Session最終被廢棄的時候,在該HTTP Session作用域內的bean也會被廢棄掉。
<bean id="role" class="spring.chapter2.maryGame.Role" scope="session"/>
3.4. global session作用域
考慮下面bean定義:
global session作用域類似於標準的HTTP Session作用域,不過它僅僅在基於portlet的web應用中才有意義。Portlet規範定義了全局Session的概念,它被所有構成某個portlet web應用的各種不同的portlet所共享。在global session作用域中定義的bean被限定於全局portlet Session的生命週期範圍內。
請注意,假如你在編寫一個標準的基於Servlet的web應用,並且定義了一個或多個具有global session作用域的bean,系統會使用標準的HTTP Session作用域,並且不會引起任何錯誤。
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
3.5. 作用域bean與依賴
能夠在HTTP request或者Session(甚至自定義)作用域中定義bean固然很好,但是Spring IoC容器除了管理對象(bean)的實例化,同時還負責協作者(或者叫依賴)的實例化。如果你打算將一個Http request範圍的bean注入到另一個bean中,那麼需要注入一個AOP代理來替代被注入的作用域bean。也就是說,你需要注入一個代理對象,該對象具有與被代理對象一樣的公共接口,而容器則可以足夠智能的從相關作用域中(比如一個HTTP request)獲取到真實的目標對象,並把方法調用委派給實際的對象。
不能和作用域爲singleton或prototype的bean一起使用。爲singleton bean創建一個scoped proxy將拋出BeanCreationException異常。 |
4.引入簡單singleton實例:
配置文件:spring-relation.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"
default-autowire="byName" default-lazy-init="true">
<!-- 使用bean的scope屬性來配置bean的作用域
singleton:默認值,容器初始化時創建bean實例,在整個容器的生命週期內只創建這一個bean,單例的
prototype:一個bean定義對應多個對象實例。
request:在一次HTTP請求中,一個bean定義對應一個實例;即每次HTTP請求將會有各自的bean實例,它們依據某個bean定義創建而成。該作用域僅在基於web的Spring ApplicationContext情形下有效。
session:在一個HTTP Session中,一個bean定義對應一個實例。該作用域僅在基於web的Spring ApplicationContext情形下有效。f
global session:在一個全局的HTTP Session中,一個bean定義對應一個實例。典型情況下,僅在使用portlet context的時候有效。該作用域僅在基於web的Spring ApplicationContext情形下有效。 -->
<bean id="car" scope="singleton" class="com.zd.runsharing.maven.springAutowire.Car">
<property name="brand" value="寶馬啊汽車品牌"></property>
<property name="price" value="43000000"></property>
</bean>
</beans>
Car類:
public class Car {
public Car() {
System.out.println("Car .. constractor....");
}
private String brand;
private double price;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Car [brand=" + brand + ", price=" + price + "]";
}
}
主函數測試類:
public class BeanRelationMainTest {
public static void main(String[] args) {
ApplicationContext atx = new ClassPathXmlApplicationContext("spring-relation.xml");
Car car = (Car) atx.getBean("car");
Car car2 = (Car) atx.getBean("car");
System.out.println(car == car2);
}
}
運行結果:
=================================================================================
=================================================================================
=================================================================================