【Spring】bean的作用域(@Scope) - singleton、prototype
? 已知spring 3+已擁有多種不同的作用域: singleton(默認(rèn))、prototype、request、session、global session。(參考: spring中scope作用域(轉(zhuǎn)))
? 到目前為止,其實還沒在項目中實際遇到要修改作用域的情況。
? 但卻知道有大概類似這么一種說法: spring的bean中不允許(或不建議)定義成員變量,不管是public還是private。
? 但之前在做一個功能的時候確實遇到了想在service定義一個成員變量Map類型的,但有映像spring中默認(rèn)是單例,結(jié)合單例的特性??紤]到可能定義成員變量有問題,所以就重新回來看一下。
? (最后也沒采用定義成員變量的方式,還是用的參數(shù)傳遞。)?
一、測試singleton、prototype的差異
? 1.1 singleton主要測試代碼
@Controller
@Scope("singleton")
public class SingletonController {@Autowiredprivate SingletonService singletonService;private Integer controllerIndex = 1;@RequestMapping("/singleton")@ResponseBodypublic Map<String, Object> singleton(){Map<String, Object> rs = new HashMap<>();rs.put("service_index",singletonService.getIndex());rs.put("controller_index",controllerIndex);rs.put("controller_hashCode",this.hashCode());rs.put("service_hashCode",singletonService.hashCode());rs.put("cache",singletonService.getCache());return rs;}
}@Service
@Scope("singleton")
public class SingletonService {private Map<String,Object> cache = new HashMap<>();private Integer index = 1;public Map<String, Object> getCache() {return cache;}public Integer getIndex() {cache.put("index-"+index,index);return index++;}
}? 結(jié)果猜想:
??? 1) 每次請求后controller_index、service_index都在遞增。
??? 2) controller_hashCode、service_hashCode每次都保持不變,因為單例只有一個實例。(java中得不到內(nèi)存地址,變相的hashCode在一定情況下可以表示內(nèi)存)
??? 3) cache的key/value一直在增多,請求一次多一個。
? 這些全部都符合單例的特性。
? 1.2 prototype主要測試代碼
@Controller
@Scope("prototype")
public class PrototypeController {@Autowiredprivate PrototypeService prototypeService;private Integer controllerIndex = 1;@RequestMapping("/prototype")@ResponseBodypublic Map<String, Object> singleton(){Map<String, Object> rs = new HashMap<>();rs.put("service_index",prototypeService.getIndex());rs.put("controller_index",controllerIndex);rs.put("controller_hashCode",this.hashCode());rs.put("service_hashCode",prototypeService.hashCode());rs.put("cache",prototypeService.getCache());return rs;}
}@Service
@Scope("prototype")
public class PrototypeService {private Map<String,Object> cache = new HashMap<>();private Integer index = 1;public Map<String, Object> getCache() {return cache;}public Integer getIndex() {cache.put("index-"+index,index);return index++;}
}? 結(jié)果猜想:
??? 1) controller_index、service_index始終都是1。
??? 2) controller_hashCode、service_hashCode每次都在改變。
??? 3) cache只有一個key/value,即{"index-1": 1}。
? 1.3 結(jié)論
??? 實際的結(jié)果和猜想完全符合,就是簡單的單例/多例的區(qū)別。
??? 所以如果存在類似的代碼:
??? 想現(xiàn)在aMethod()中處理一些邏輯,然后把符合的保存起來供bMethod()使用。并且你簡單的測試不會有問題,因為是單線程的測試。
??? 但現(xiàn)在整體來看,如果多個用戶同時操作。本來A是put(1,"a"),但是此時B又緊接著put(1,"b")。A先進入bMethod(),那么get(1) = "b",這就是明顯的多線程并發(fā)問題。
??? 當(dāng)然可以把Scope改成prototype,但現(xiàn)在的處境是: 1) 沒絕對的比較。2) 整個項目中并沒有用prototype的先例。
??? 所以最常見的作法是改成方法傳參:
@Service
@Scope("singleton")
public class SingletonService {public void aMethod() {private Map<String,Object> cache = new HashMap<>();// 一些邏輯cache.put(...);bMethod();}public void bMethod(Map<String,Object> cache) {Object obj = cache.get(...);// 一些邏輯}
}二、此文的真正目的
? 簡單目的: 在spring默認(rèn)情況下的bean中定義成員變量帶來的風(fēng)險。
? 但,其實是記錄spring是怎么解決線程安全的。(詳見: Spring單例與線程安全小結(jié))
? 我個人對線程也不是足夠了解,去零零碎碎看過,但實際項目中確實還沒完全真正的結(jié)果過。
? 但在以前看過過一篇文章(就是上面那篇),寫spring是怎么解決線程安全的,寫spring利用的不是線程同步機制(synchronized)而是用的ThreadLocal。
? 這只記錄下兩者的差異,主要還是上面那篇博客中說的。
? synchronized: 時間換空間,以較慢的執(zhí)行時間來節(jié)約空間的被占用。
在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析什么時候?qū)ψ兞窟M行讀寫,什么時候需要鎖定某個對象,什么時候釋放對象鎖等繁雜的問題,程序設(shè)計和編寫難度相對較大。
? ThreadLocal: 空間換時間,占用更多的空間來換取較快的執(zhí)行時間。
在ThreadLocal中,會為每一個線程提供一個獨立的變量副本,從而隔離了多個線程對數(shù)據(jù)的訪問沖突。因為每一個線程都擁有自己的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,可以把不安全的變量封裝進ThreadLocal。
?
? ps: 最近很長一段時間一直相當(dāng)煩躁,此文章本來很簡單,但寫到最后我自己都不知道自己到底想表達什么、想記錄什么....感覺更像應(yīng)付式的給自己一個任務(wù),形式一般的寫一篇文章....
轉(zhuǎn)載于:https://www.cnblogs.com/VergiLyn/p/6965571.html
總結(jié)
以上是生活随笔為你收集整理的【Spring】bean的作用域(@Scope) - singleton、prototype的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于人鬼恋的电影都有啥
- 下一篇: 战地一多少钱