摘自:http://jinnianshilongnian.iteye.com/blog/1415463
Bean的作用域
什么是作用域呢?即“scope”,在面向?qū)ο蟪绦蛟O(shè)計中一般指對象或變量之間的可見范圍先改。而在Spring容器中是指其創(chuàng)建的Bean對象相對于其他Bean對象的請求可見范圍蒸走。
Spring提供“singleton”和“prototype”兩種基本作用域,另外提供“request”该溯、“session”别惦、“global session”三種web作用域;Spring還允許用戶定制自己的作用域氯庆。
基本的作用域
singleton:
指“singleton”作用域的Bean只會在每個Spring IoC容器中存在一個實例扰付,而且其完整生命周期完全由Spring容器管理。對于所有獲取該Bean的操作Spring容器將只返回同一個Bean实昨。
GoF單例設(shè)計模式指“保證一個類僅有一個實例荒给,并提供一個訪問它的全局訪問點”,介紹了兩種實現(xiàn):通過在類上定義靜態(tài)屬性保持該實例和通過注冊表方式志电。
1)通過在類上定義靜態(tài)屬性保持該實例:
一般指一個Java虛擬機 ClassLoader裝載的類只有一個實例蛔趴,一般通過類靜態(tài)屬性保持該實例,這樣就造成需要單例的類都需要按照單例設(shè)計模式進(jìn)行編碼之拨;Spring沒采用這種方式咧叭,因為該方式屬于侵入式設(shè)計菲茬。
public class Singleton {
//1.私有化構(gòu)造器
private Singleton() {}
//2.單例緩存者,惰性初始化睬魂,第一次使用時初始化
private static class InstanceHolder {
private static final Singleton INSTANCE = new Singleton();
}
//3.提供全局訪問點
public static Singleton getInstance() {
return InstanceHolder.INSTANCE;
}
//4.提供一個計數(shù)器來驗證一個ClassLoader一個實例
private int counter=0;
}
2)通過注冊表方式:
首先將需要單例的實例通過唯一鍵注冊到注冊表氯哮,然后通過鍵來獲取單例商佛,讓我們直接看實現(xiàn)吧,注意本注冊表實現(xiàn)了Spring接口“SingletonBeanRegistry”肠虽,該接口定義了操作共享的單例對象玛追,Spring容器實現(xiàn)將實現(xiàn)此接口;所以共享單例對象通過“registerSingleton”方法注冊韩玩,通過“getSingleton”方法獲取陆馁,消除了編程方式單例。
public class SingletonBeanRegister implements SingletonBeanRegistry {
//單例Bean緩存池叮雳,此處不考慮并發(fā)
private final Map<String, Object> BEANS = new HashMap<String, Object>();
public boolean containsSingleton(String beanName){
return BEANS.containsKey(beanName);
}
public Object getSingleton(String beanName) {
return BEANS.get(beanName);
}
@Override
public int getSingletonCount() {
return BEANS.size();
}
@Override
public String[] getSingletonNames() {
return BEANS.keySet().toArray(new String[0]);
}
@Override
public void registerSingleton(String beanName, Object bean) {
if(BEANS.containsKey(beanName)) {
throw new RuntimeException("[" + beanName + "] 已存在");
}
BEANS.put(beanName, bean);
}
}
Spring是注冊表單例設(shè)計模式的實現(xiàn)帘不,消除了編程式單例寞焙,而且對代碼是非入侵式互婿。
接下來讓我們看看在Spring中如何配置單例Bean吧,在Spring容器中如果沒指定作用域默認(rèn)就是“singleton”呛牲,配置方式通過scope屬性配置驮配,具體配置如下:
<bean class="cn.javass.spring.chapter3.bean.Printer" scope="singleton"/>
Spring不僅會緩存單例對象着茸,Bean定義也是會緩存的涮阔,對于惰性初始化的對象是在首次使用時根據(jù)Bean定義創(chuàng)建并存放于單例緩存池灰殴。
prototype:
即原型,指每次向Spring容器請求獲取Bean都返回一個全新的Bean伟阔,相對于“singleton”來說就是不緩存Bean义图,每次都是一個根據(jù)Bean定義創(chuàng)建的全新Bean。
GoF原型設(shè)計模式娃承,指用原型實例指定創(chuàng)建對象的種類怕篷,并且通過拷貝這些原型創(chuàng)建新的對象。
Spring中的原型和GoF中介紹的原型含義是不一樣的:
- GoF通過用原型實例指定創(chuàng)建對象的種類梳猪,而Spring容器用Bean定義指定創(chuàng)建對象的種類蒸痹;
- GoF通過拷貝這些原型創(chuàng)建新的對象,而Spring容器根據(jù)Bean定義創(chuàng)建新對象匿沛。
其相同地方都是根據(jù)某些東西創(chuàng)建新東西逃呼,而且GoF原型必須顯示實現(xiàn)克隆操作,屬于侵入式抡笼,而Spring容器只需配置即可黄鳍,屬于非侵入式。
只需指定<bean>標(biāo)簽屬性“scope”屬性為“prototype”即可:
<bean class="cn.javass.spring.chapter3.bean.Printer" scope="prototype"/>
Spring管理原型對象在Spring容器中存儲如圖3-6所示拾碌,Spring不會緩存原型對象街望,而是根據(jù)Bean定義每次請求返回一個全新的Bean:
Web應(yīng)用中的作用域
在Web應(yīng)用中,我們可能需要將數(shù)據(jù)存儲到request防症、session哎甲、global session。因此Spring提供了三種Web作用域:request奈嘿、session吞加、globalSession。
一衔憨、request作用域:
表示每個請求需要容器創(chuàng)建一個全新Bean。比如提交表單的數(shù)據(jù)必須是對每次請求新建一個Bean來保持這些表單數(shù)據(jù)掺冠,請求結(jié)束釋放這些數(shù)據(jù)码党。
二、session作用域:
表示每個會話需要容器創(chuàng)建一個全新Bean眉厨。比如對于每個用戶一般會有一個會話缺猛,該用戶的用戶信息需要存儲到會話中椭符,此時可以將該Bean配置為web作用域。
三销钝、globalSession:
類似于session作用域蒸健,只是其用于portlet環(huán)境的web應(yīng)用婉商。如果在非portlet環(huán)境將視為session作用域丈秩。
配置方式和基本的作用域相同淳衙,只是必須要有web環(huán)境支持,并配置相應(yīng)的容器監(jiān)聽器或攔截器從而能應(yīng)用這些作用域肠牲,我們會在集成web時講解具體使用靴跛,大家只需要知道有這些作用域就可以了。