當經過spring容器建立一個Bean實例時,不只能夠完成Bean實例的實例化,還能夠爲Bean指定特定的做用域。Spring支持以下5種做用域:web
singleton:單例模式,在整個Spring IoC容器中,使用singleton定義的Bean將只有一個實例面試
prototype:原型模式,每次經過容器的getBean方法獲取prototype定義的Bean時,都將產生一個新的Bean實例spring
request:對於每次HTTP請求,使用request定義的Bean都將產生一個新實例,即每次HTTP請求將會產生不一樣的Bean實例。只有在Web應用中使用Spring時,該做用域纔有效安全
session:對於每次HTTP Session,使用session定義的Bean豆漿產生一個新實例。一樣只有在Web應用中使用Spring時,該做用域纔有效session
globalsession:每一個全局的HTTP Session,使用session定義的Bean都將產生一個新實例。典型狀況下,僅在使用portlet context的時候有效。一樣只有在Web應用中使用Spring時,該做用域纔有效mvc
其中比較經常使用的是singleton和prototype兩種做用域。對於singleton做用域的Bean,每次請求該Bean都將得到相同的實例。容器負責跟蹤Bean實例的狀態,負責維護Bean實例的生命週期行爲;若是一個Bean被設置成prototype做用域,程序每次請求該id的Bean,Spring都會新建一個Bean實例,而後返回給程序。在這種狀況下,Spring容器僅僅使用new 關鍵字建立Bean實例,一旦建立成功,容器不在跟蹤實例,也不會維護Bean實例的狀態。app
若是不指定Bean的做用域,Spring默認使用singleton做用域。Java在建立Java實例時,須要進行內存申請;銷燬實例時,須要完成垃圾回收,這些工做都會致使系統開銷的增長。所以,prototype做用域Bean的建立、銷燬代價比較大。而singleton做用域的Bean實例一旦建立成功,能夠重複使用。所以,除非必要,不然儘可能避免將Bean被設置成prototype做用域。性能
曾經面試的時候有面試官問我spring的controller是單例仍是多例,結果我傻逼的回答固然是多例,要否則controller類中的非靜態變量如何保證是線程安全的,這樣想起彷佛是對的,可是不知道(主要是我沒看過spring的源碼,不知道真正的內在乎圖)爲何spring的controller是單例的。先看看spring的bean做用域有幾種,分別有啥不一樣。spring bean做用域有如下5個:singleton:單例模式,當spring建立applicationContext容器的時候,spring會欲初始化全部的該做用域實例,加上lazy-init就能夠避免預處理;prototype:原型模式,每次經過getBean獲取該bean就會新產生一個實例,建立後spring將再也不對其管理;====下面是在web項目下才用到的===request:搞web的你們都應該明白request的域了吧,就是每次請求都新產生一個實例,和prototype不一樣就是建立後,接下來的管理,spring依然在監聽session:每次會話,同上global session:全局的web域,相似於servlet中的application好了,上面都說了spring的controller默認是單例,那很天然就是singleton了。再看一個例子,看看單例會不會有我說的那種問題(就是類中定義的非靜態變量線程安全問題),固然下面這個例子我是實驗過的, 要否則也不敢發出來爲何spring要默認是單例呢?緣由有二:一、爲了性能。二、不須要多例。一、這個不用廢話了,單例不用每次都new,固然快了。二、不須要實例會讓不少人迷惑,由於spring mvc官方也沒明確說不能夠多例。 我這裏說不須要的緣由是看開發者怎麼用了,若是你給controller中定義不少的屬性,那麼單例確定會出現競爭訪問了。 所以,只要controller中不定義屬性,那麼單例徹底是安全的。下面給個例子說明下: 默認單例的1|2package com.lavasoft.demo.web.controller.lsh.ch5;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Controller;import org.springframework.ui.ModelMap;import org.springframework.web.bind.annotation.RequestMapping;/** * Created by Administrator on 14-4-9. * * @author leizhimin 14-4-9 上午10:55 */@Controller@RequestMapping("/demo/lsh/ch5")public class MultViewController {privateintindex =0; //非靜態 @RequestMapping("/show") publicStringtoShow(ModelMap model) { System.out.println(++i); return"/lsh/ch5/show"; } @RequestMapping("/test") publicStringtest() { System.out.println(++i); return"/lsh/ch5/test"; }}改成多例的(就是在class上面加一個@Scope("request")):1 | 1今後可見,單例是不安全的,會致使屬性重複使用。最佳實踐:一、不要在controller中定義成員變量。二、萬一必需要定義一個非靜態成員變量時候,則經過註解@Scope("prototype"),將其設置爲多例模式。