Spring提供了5種scope分別是singleton濒旦、prototype、request再登、session尔邓、global session。
官方文檔介紹:
單例bean與原型bean的區(qū)別
-
單例:一個bean被聲明為單例時锉矢,處理多次請求時spring容器里只實例化一個bean梯嗽,后續(xù)的請求公用這個對象,這個對象存儲在一個map中沽损,當(dāng)有請求時灯节,先在緩存中(map)查找是否存在,存在則使用,不存在才實例化一個對象
原型:每當(dāng)有請求來就實例化一個新的bean炎疆,沒有緩存以及從緩存中查
源碼分析
- 生成bean時先判斷單例的還是原型
- 如果是單例的則先嘗試從緩存里獲取卡骂,沒有在新創(chuàng)建
結(jié)論:
1、單例的bean只有第一次創(chuàng)建新的bean 后面都會復(fù)用該bean形入,所以不會頻繁創(chuàng)建對象全跨。
2、原型的bean每次都會新創(chuàng)建
單例bean的優(yōu)勢
由于不會每次都新創(chuàng)建新對象所以有一下幾個性能上的優(yōu)勢:
減少了新生成實例的消耗
新生成實例消耗包括兩方面亿遂,第一浓若,spring會通過反射或者cglib來生成bean實例這都是耗性能的操作,其次給對象分配內(nèi)存也會涉及復(fù)雜算法蛇数。減少jvm垃圾回收
由于不會給每個請求都新生成bean實例挪钓,所以自然回收的對象少了。可以快速獲取到bean
因為單例的獲取bean操作除了第一次生成之外其余的都是從緩存里獲取的所以很快耳舅。
單例bean的劣勢
單例的bean一個很大的劣勢就是他不能做到線程安全
诵原,由于所有請求都共享一個bean實例,所以這個bean要是有狀態(tài)的一個bean的話可能在并發(fā)場景下出現(xiàn)問題挽放,而原型的bean則不會有這樣問題(但也有例外绍赛,比如他被單例bean依賴),因為給每個請求都新創(chuàng)建實例辑畦。
總結(jié)
面試題:Spring 為啥把bean默認(rèn)設(shè)計成單例吗蚌?
答案:
- 為了提高性能
- 少創(chuàng)建實例*
- 垃圾回收
- 緩存快速獲取
單例有啥劣勢?
如果是有狀態(tài)的話在并發(fā)環(huán)境下線程不安全纯出。
什么是有狀態(tài)對象蚯妇?什么是無狀態(tài)對象?
有狀態(tài)對象:有實例變量可以標(biāo)志其對象所處的狀態(tài)暂筝。(有實例變量的對象箩言,有存儲數(shù)據(jù)能力)- 白話:有屬性的對象
無狀態(tài)對象:無實例變量可以標(biāo)志其對象所處的狀態(tài)。(無實例變量的對象焕襟,無存儲數(shù)據(jù)能力)- 白話:無屬性的對象