Spring Bean的作用域有singleton诚亚、prototype赖草、request杆逗、session、application鳞疲、websocket罪郊。
singleton
singleton就是常見(jiàn)的單例模式的一種實(shí)現(xiàn),默認(rèn)情況下bean的作用域就是singleton尚洽,所以無(wú)需做任何配置悔橄。
需要注意的是這里所指的單例并不是應(yīng)用程序中的單例,而是在當(dāng)前bean容器中是單例的腺毫。當(dāng)bean被定義為單例時(shí)癣疟,spring容器中會(huì)共享這個(gè)bean實(shí)例。
prototype
當(dāng)bean的scope設(shè)定為prototype時(shí)潮酒,如果這個(gè)bean需要被引用(注入到某個(gè)bean中或者被getBean()方式查找)睛挚,spring容器都會(huì)根據(jù)當(dāng)前bean定義創(chuàng)建一個(gè)全新的bean實(shí)例對(duì)象返回。
實(shí)現(xiàn)方式
- 通過(guò)xml配置
<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>
- 通過(guò)@Scope
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- 通過(guò)BeanDefinitionBuilder#setScope
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition (User.class);
builder.addPropertyValue ("name", "bd-user")
.setScope (BeanDefinition.SCOPE_PROTOTYPE);
request & session & application
這幾個(gè)作用域只能web環(huán)境中有效急黎,如果是在非web的spring環(huán)境使用這些作用域竞川,容器會(huì)拋出IllegalStateException。
request
被定義成request作用域叁熔,即每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例委乌。
session
被定義成session作用域,即在同一個(gè)session環(huán)境中共享bean實(shí)例
application
被定義成application作用域荣回,即在servlet上下文環(huán)境中共享bean實(shí)例
singleton類(lèi)型bean注入prototype類(lèi)型bean問(wèn)題
因?yàn)閎ean的依賴(lài)關(guān)系是在實(shí)例化時(shí)解析完成的遭贸,所以singleton類(lèi)型bean中的注入prototype類(lèi)型bean的過(guò)程也是只有一次,那么其實(shí)每次使用的都是同一個(gè)prototype類(lèi)型bean對(duì)象心软。
如果想singleton類(lèi)型bean在運(yùn)行時(shí)重新獲取新的prototype類(lèi)型bean實(shí)例壕吹,spring提供了method injection的方式解決這個(gè)問(wèn)題 【方法注入非這次的學(xué)習(xí)重點(diǎn),暫不過(guò)多論述】删铃。
源碼解析
源碼入口,作用域判斷的主要邏輯在AbstractBeanFactory的doGetBean:
//調(diào)用棧
AbstractApplicationContext#refresh
->AbstractApplicationContext#finishBeanFactoryInitialization
->AbstractApplicationContext#preInstantiateSingletons
->DefaultListableBeanFactory#preInstantiateSingletons
->AbstractBeanFactory#getBean
->AbstractBeanFactory#doGetBean
-
下圖是作用域?yàn)镾ingleton的處理入口
-
下圖是作用域?yàn)镻rototype的處理入口
-
下圖是其他作用域的處理入口耳贬,如request、session猎唁、application咒劲、websocket、自定義作用域
request&session的處理入口
-
request和session的處理入口是AbstractRequestAttributesScope#get
application的處理入口
-
application的處理入口時(shí)ServletContextScope#get