spring bean scope作用域及多線程安全問題場景分析

Scope作用域

在 Spring IoC 容器中具有以下幾種作用域:

  • singleton:單例模式刘莹,在整個(gè)Spring IoC容器中负饲,使用singleton定義的Bean將只有一個(gè)實(shí)例部逮,適用于無狀態(tài)bean;
  • prototype:原型模式,每次通過容器的getBean方法獲取prototype定義的Bean時(shí)夭织,都將產(chǎn)生一個(gè)新的Bean實(shí)例赌结,適用于有狀態(tài)的Bean捞蛋;
  • request:對(duì)于每次HTTP請(qǐng)求,使用request定義的Bean都將產(chǎn)生一個(gè)新實(shí)例柬姚,即每次HTTP請(qǐng)求將會(huì)產(chǎn)生不同的Bean實(shí)例拟杉。只有在Web應(yīng)用中使用Spring時(shí),該作用域才有效量承;
  • session:對(duì)于每次HTTP Session搬设,使用session定義的Bean豆?jié){產(chǎn)生一個(gè)新實(shí)例。同樣只有在Web應(yīng)用中使用Spring時(shí)撕捍,該作用域才有效拿穴;
  • globalsession:每個(gè)全局的HTTP Session,使用session定義的Bean都將產(chǎn)生一個(gè)新實(shí)例忧风。典型情況下默色,僅在使用portlet context的時(shí)候有效。同樣只有在Web應(yīng)用中使用Spring時(shí)狮腿,該作用域才有效腿宰。

@scope默認(rèn)是單例模式(singleton),如果需要設(shè)置的話@scope("prototype")
或xml配置如下:

<bean id="service1" class="com.test.TestServiceImpl1" scope="singleton" />  
<bean id="service2" class="com.test.TestServiceImpl2" scope="prototype" />  

無狀態(tài)會(huì)話bean

bean一旦實(shí)例化就被加進(jìn)會(huì)話池中,各個(gè)用戶都可以共用缘厢。即使用戶已經(jīng)消亡吃度,bean 的生命期也不一定結(jié)束,它可能依然存在于會(huì)話池中贴硫,供其他用戶調(diào)用椿每。
由于沒有特定的用戶,那么也就不能保持某一用戶的狀態(tài),所以叫無狀態(tài)bean间护。但無狀態(tài)會(huì)話bean 并非沒有狀態(tài)删壮,如果它有自己的屬性(變量),那么這些變量就會(huì)受到所有調(diào)用它的用戶的影響兑牡。

有狀態(tài)會(huì)話bean

每個(gè)用戶有自己特有的一個(gè)實(shí)例央碟,在用戶的生存期內(nèi),bean保持了用戶的信息均函,即“有狀態(tài)”亿虽;一旦用戶滅亡(調(diào)用結(jié)束或?qū)嵗Y(jié)束),bean的生命期也告結(jié)束苞也。即每個(gè)用戶最初都會(huì)得到一個(gè)初始的bean洛勉。

有狀態(tài)bean,如果配置為singleton如迟,會(huì)出現(xiàn)線程安全問題

示例:

package com.test;    
public class TestServiceImpl implements TestService{  
    private User user;
    public void test1(User u) throws Exception {  
        this.user = u;                          //1  
        test2();  
    }  
    
    public void test2() throws Exception {  
        System.out.println(user.getId());       //2 
    }     
}

如果該Bean配置為singleton,在并發(fā)訪問下會(huì)出現(xiàn)問題
假設(shè)有2個(gè)用戶user1,user2訪問收毫,都調(diào)用到了該Bean。
1.當(dāng)user1 調(diào)用到程序中的1步驟的時(shí)候殷勘,該Bean的私有變量user被付值為user1此再;
2.理想的狀況,當(dāng)user1走到2步驟的時(shí)候玲销,私有變量user應(yīng)該為user1;
3.但如果在user1調(diào)用到2步驟之前输拇,user2開始運(yùn)行到了1步驟了,由于單態(tài)的資源共享贤斜,則私有變量user被修改為user2策吠;
4.這種情況下,user1的步驟2用到的user.getId()實(shí)際用到是user2的對(duì)象瘩绒。
實(shí)際應(yīng)該是這個(gè)例子不應(yīng)該用實(shí)例變量猴抹,這樣就使得這個(gè)Bean由無狀態(tài)變成了有狀態(tài)Bean。

常用web架構(gòu)锁荔,線程安全問題場景分析

1.SSH架構(gòu)系統(tǒng)

對(duì)于SSH架構(gòu)的系統(tǒng)蟀给,很少關(guān)心這方面,因?yàn)槲覀冇玫降囊话愣际莝ingleton. Bean的注入由Spring管理堕战。

Struts2中的Action因?yàn)闀?huì)有User這樣的實(shí)例對(duì)象坤溃,是有狀態(tài)信息的拍霜,在多線程環(huán)境下是不安全的嘱丢,所以Struts2默認(rèn)的實(shí)現(xiàn)是Prototype模式。也就是每個(gè)請(qǐng)求都新生成一個(gè)Action實(shí)例祠饺,所以不存在線程安全問題越驻。需要注意的是,如果由Spring管理action的生命周期, scope要配成prototype作用域缀旁。

Struts1是基于單例模式實(shí)現(xiàn)记劈,也就是只有一個(gè)Action實(shí)例供多線程使用。默認(rèn)的模式是前臺(tái)頁面數(shù)據(jù)通過actionForm傳入并巍,在action中的excute方法接收目木,這樣action是無狀態(tài)的,所以一般情況下Strunts1是線程安全的懊渡。如果Action中用了實(shí)例變量刽射,那么就變成有狀態(tài)了,同樣是非線程安全的剃执。像下面這樣就是線程不安全的誓禁。

/** 
 * 非線程安全的Struts1示例  
 *  
 */  
public class UserAction extends Action {  
    // 因?yàn)镾truts1是單例實(shí)現(xiàn),有狀態(tài)情況下肾档,對(duì)象引用是非線程安全的  
    private User user;  
    public void execute() {  
        // do something...  
    }  
    public User getUser() {  
        return user;  
    }  
    public void setUser(User user) {  
        this.user = user;  
    }  
}  

2.Servlet

Servlet體系結(jié)構(gòu)是建立在Java多線程機(jī)制之上的摹恰,它的生命周期是由Web 容器負(fù)責(zé)的。
一個(gè)Servlet類在Application中只有一個(gè)實(shí)例存在怒见,有多個(gè)線程在使用這個(gè)實(shí)例俗慈。這是單例模式的應(yīng)用。
無狀態(tài)的單例是線程安全的遣耍,但我們?nèi)绻赟ervlet里用了實(shí)例變量(私有變量)姜盈,那么就變成有狀態(tài)了,是非線程安全的配阵。
如下面的用法就是不安全的,因?yàn)閡ser是有狀態(tài)信息的馏颂。

public class UserServlet HttpServlet{     
    private User user;   
    public void doGet (HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{  
        //do something...  
    }  
} 

總結(jié)

  • singleton會(huì)造成資源混亂問題,而如果是prototype的話,就不會(huì)出現(xiàn)資源共享的問題棋傍。(即不會(huì)出現(xiàn)線程安全的問題)
  • 應(yīng)該盡量使用無狀態(tài)Bean.如果在程序中出現(xiàn)私有變量(該bean會(huì)變?yōu)橛袪顟B(tài)的救拉,一旦在其他線程中發(fā)生改變,就會(huì)產(chǎn)生線程不安全)瘫拣,解決方案就是盡量替換為方法中的參數(shù)亿絮。對(duì)于每個(gè)訪問私有變量的方法增加變量傳入(參數(shù)傳入)或者通過ThreadLocal來獲取。
  • 如果用有狀態(tài)的bean麸拄,就要用prototype模式派昧,每次在注入的時(shí)候就重新創(chuàng)建一個(gè)bean,在多線程中互不影響拢切。
  • 如Service層蒂萎、Dao層用默認(rèn)singleton就行,雖然Service類也有dao這樣的屬性淮椰,但dao這些類都是沒有狀態(tài)信息的五慈,也就是相當(dāng)于不變(immutable)類纳寂,所以不影響。
  • Stateless無狀態(tài)用單例Singleton模式泻拦,Stateful有狀態(tài)就用原型Prototype模式毙芜。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市争拐,隨后出現(xiàn)的幾起案子腋粥,更是在濱河造成了極大的恐慌,老刑警劉巖架曹,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件灯抛,死亡現(xiàn)場離奇詭異,居然都是意外死亡音瓷,警方通過查閱死者的電腦和手機(jī)对嚼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绳慎,“玉大人纵竖,你說我怎么就攤上這事⌒臃撸” “怎么了靡砌?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長珊楼。 經(jīng)常有香客問我通殃,道長,這世上最難降的妖魔是什么厕宗? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任画舌,我火速辦了婚禮,結(jié)果婚禮上已慢,老公的妹妹穿的比我還像新娘曲聂。我一直安慰自己,他們只是感情好佑惠,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布朋腋。 她就那樣靜靜地躺著,像睡著了一般膜楷。 火紅的嫁衣襯著肌膚如雪旭咽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天赌厅,我揣著相機(jī)與錄音穷绵,去河邊找鬼。 笑死察蹲,一個(gè)胖子當(dāng)著我的面吹牛请垛,可吹牛的內(nèi)容都是我干的催训。 我是一名探鬼主播洽议,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼宗收,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了亚兄?” 一聲冷哼從身側(cè)響起混稽,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎审胚,沒想到半個(gè)月后匈勋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膳叨,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年洽洁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片菲嘴。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡饿自,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出龄坪,到底是詐尸還是另有隱情昭雌,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布健田,位于F島的核電站烛卧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏妓局。R本人自食惡果不足惜总放,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望好爬。 院中可真熱鬧间聊,春花似錦、人聲如沸抵拘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽僵蛛。三九已至尚蝌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間充尉,已是汗流浹背飘言。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驼侠,地道東北人姿鸿。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓谆吴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親苛预。 傳聞我的和親對(duì)象是個(gè)殘疾皇子句狼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)热某,斷路器腻菇,智...
    卡卡羅2017閱讀 134,713評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法昔馋,內(nèi)部類的語法筹吐,繼承相關(guān)的語法,異常的語法秘遏,線程的語...
    子非魚_t_閱讀 31,664評(píng)論 18 399
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,859評(píng)論 6 342
  • 從三月份找實(shí)習(xí)到現(xiàn)在丘薛,面了一些公司,掛了不少邦危,但最終還是拿到小米洋侨、百度、阿里铡俐、京東凰兑、新浪、CVTE审丘、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,278評(píng)論 11 349
  • 文章作者:Tyan博客:noahsnail.com 3.5 Bean scopes When you create...
    SnailTyan閱讀 1,893評(píng)論 0 1