Spring 5.0.0框架介紹_中文版_3.5

文章作者:Tyan
博客:noahsnail.com

3.5 Bean的作用域

????????當(dāng)你創(chuàng)建bean定義時(shí),你創(chuàng)建了一個(gè)配方用于創(chuàng)建bean定義中定義的類(lèi)的實(shí)例。bean定義是配方的想法是很重要的,因?yàn)檫@意味著對(duì)于一個(gè)類(lèi),你可以根據(jù)一個(gè)配方創(chuàng)建許多對(duì)象實(shí)例。

????????你不僅能管理要插入對(duì)象中的的各種依賴(lài)和配置值,而且能管理對(duì)象的作用域,對(duì)象是從特定的bean定義中創(chuàng)建的。這種方法是強(qiáng)大且靈活的,你可以通過(guò)配置文件選擇你創(chuàng)建的對(duì)象的作用域,從而代替Java類(lèi)級(jí)別對(duì)象的內(nèi)置作用域。定義的beans將部署成多種作用域中的一種:開(kāi)箱即用,Spring框架支持六種作用域,如果你使用感知web的ApplicationContext,你只可以使用其中的五種作用域。

????????下面的作用域支持開(kāi)箱即用。你也可以創(chuàng)建一個(gè)定制的作用域。

表 3.3 bean作用域

作用域 描述
singleton (默認(rèn)) 每個(gè)Spring IoC容器使單個(gè)bean定義只能創(chuàng)建一個(gè)對(duì)象實(shí)例。
prototype 單個(gè)bean定義可以創(chuàng)建任何數(shù)量的對(duì)象實(shí)例。
request 單個(gè)bean定義的創(chuàng)建實(shí)例的作用域?yàn)閱蝹€(gè)HTTP request的聲明周期;也就是說(shuō),每個(gè)HTTP request有它自己的根據(jù)bean定義創(chuàng)建的實(shí)例。只在感知Spring ApplicationContext的上下文中有效。
session 單個(gè)bean定義的創(chuàng)建實(shí)例的作用域?yàn)镠TTP Session的生命周期. 只在感知Spring ApplicationContext的上下文中有效。
application 單個(gè)bean定義的創(chuàng)建實(shí)例的作用域?yàn)?code>ServletContext的生命周期。 只在感知Spring ApplicationContext的上下文中有效。
websocket 單個(gè)bean定義的創(chuàng)建實(shí)例的作用域?yàn)?code>WebSocket的生命周期。 只在感知Spring ApplicationContext的上下文中有效。

從Spring 3.0,引入了thread scope作用域,但默認(rèn)情況下是不注冊(cè)的。更多的信息請(qǐng)看SimpleThreadScope文檔。關(guān)于怎么注冊(cè)thread scope作用域或任何其它的定制作用域的介紹,請(qǐng)看『Using a custom scope』小節(jié)。

3.5.1 單例作用域

????????單例bean只管理一個(gè)共享實(shí)例,id匹配bean定義的所有對(duì)beans的請(qǐng)求,Spring容器會(huì)返回一個(gè)特定的bean實(shí)例。

????????換言之,當(dāng)你定義一個(gè)bean定義時(shí),它的作用域?yàn)閱卫?,Spring IoC容器會(huì)根據(jù)bean定義創(chuàng)建一個(gè)確定的對(duì)象實(shí)例。這個(gè)單獨(dú)的實(shí)例存儲(chǔ)在單例beans的緩存中,接下來(lái)的對(duì)這個(gè)命名bean的所有請(qǐng)求和引用都會(huì)返回那個(gè)緩存的對(duì)象。

image

????????Spring中的單例bean概念不同于《設(shè)計(jì)模式》書(shū)中定義的單例模式。設(shè)計(jì)模式中的單例是對(duì)對(duì)象的作用域進(jìn)行硬編碼,為的是每個(gè)類(lèi)加載器只能創(chuàng)建一個(gè)特定類(lèi)的實(shí)例。Spring單例作用域最好的描述是每個(gè)容器每個(gè)類(lèi)。這意味著如果你在單個(gè)的Spring容器中為一個(gè)特定的類(lèi)定義了一個(gè)bean,Spring只會(huì)根據(jù)bean定義創(chuàng)建一個(gè)類(lèi)的實(shí)例。在Spring中單例作用域是默認(rèn)的作用域。為了在XML定義一個(gè)單例bean,你可以像下面一樣寫(xiě),例如:

<bean id="accountService" class="com.foo.DefaultAccountService"/>

<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>

3.5.2 原型作用域

????????非單例模式,bean部署采用原型作用域時(shí),每次產(chǎn)生一個(gè)特定bean的請(qǐng)求時(shí)都會(huì)創(chuàng)建一個(gè)新的bean實(shí)例。也就是說(shuō),這個(gè)bean會(huì)注入到另一個(gè)bean中或你可以在容器中通過(guò)調(diào)用getBean()方法來(lái)請(qǐng)求它。通常,對(duì)于所有有狀態(tài)的beans使用原型作用域,對(duì)于無(wú)狀態(tài)的beans使用單例作用域。

????????下面的圖闡述了Spring原型作用域。數(shù)據(jù)訪(fǎng)問(wèn)對(duì)象(DAO)通常是不會(huì)配置為原型的,因?yàn)橐粋€(gè)典型的DAO不會(huì)有任何會(huì)話(huà)狀態(tài);對(duì)于作者來(lái)說(shuō)很容易重用單例圖的核心。

image

????????下面的例子在XML中定義一個(gè)原型bean:

<bean id="accountService" class="com.foo.DefaultAccountService" scope="prototype"/>

????????與其它作用域相比,Spring不管理原型bean的完整生命周期:容器初始化、配置,另外組裝原型對(duì)象,并把它傳遞給客戶(hù)端,之后不再記錄原型實(shí)例。因此,雖然不管什么作用域初始化生命周期回調(diào)函數(shù)都會(huì)在所有對(duì)象上調(diào)用,但是在原型作用域的情況下,不會(huì)調(diào)用配置的銷(xiāo)毀生命周期回調(diào)函數(shù)??蛻?hù)端代碼必須清理原型作用域的對(duì)象并釋放原型bean擁有的昂貴資源。為了使Spring容器釋放原型bean擁有的資源,嘗試使用定制的bean后處理程序,它擁有需要清理的bean的引用。

????????在有些方面,關(guān)于原型作用域,Spring容器的角色像是Java中new操作符的替代品。所有生命周期的管理必須由客戶(hù)端處理。(Spring容器中更多關(guān)于bean生命周期的細(xì)節(jié),請(qǐng)看3.6.1小節(jié),"生命周期回調(diào)")。

3.5.3 含有原型bean依賴(lài)的單例bean

????????當(dāng)你使用含有原型bean依賴(lài)的單例作用域bean時(shí),要意識(shí)到依賴(lài)解析是在實(shí)例化時(shí)。因此如果你使用依賴(lài)注入將原型作用域的bean注入到單例作用域的bean中時(shí),將會(huì)實(shí)例化一個(gè)新的原型bean并依賴(lài)注入到單例bean中。原型bean實(shí)例曾經(jīng)是唯一提供給單例作用域的bean的實(shí)例。

????????假設(shè)你想在運(yùn)行時(shí)讓單例作用域的bean重復(fù)的獲得原型作用域bean的新實(shí)例。你不能依賴(lài)注入原型作用域的bean到你的單例bean中,因?yàn)楫?dāng)Spring容器實(shí)例化單例bean,解析并注入它的依賴(lài)時(shí),注入只發(fā)生一次。如果你在運(yùn)行時(shí)不止一次需要原型bean的實(shí)例,請(qǐng)看3.4.6小節(jié),"方法注入"。

3.5.4 Request、session、application和 WebSocket作用域

????????如果你使用感知web的Spring ApplicationContext實(shí)現(xiàn)(例如XmlWebApplicationContext),request,sessionapplicationwebsocket作用域是唯一可用的作用域。如果你通過(guò)正規(guī)的Spring IoC容器例如ClassPathXmlApplicationContext來(lái)使用這些作用域,會(huì)拋出IllegalStateException異常,投訴使用了一個(gè)未知的bean作用域。

web配置初始化

????????為了支持request,sessionapplicationwebsocket標(biāo)準(zhǔn)的bean作用域,在你定義你的bean之前需要進(jìn)行一些較小的初始化配置。(對(duì)于標(biāo)準(zhǔn)作用域singletonprototype,初始化步驟不需要的。)

????????如果你使用Servlet 2.5的web容器,在Spring的DispatcherServlet之外處理請(qǐng)求(例如使用JSF或Struts時(shí)),你需要注冊(cè)org.springframework.web.context.request.RequestContextListener ServletRequestListener。對(duì)于Servlet 3.0+,能通過(guò)WebApplicationInitializer接口以編程方式處理。對(duì)于更早的容器,可以在應(yīng)用程序的web.xml文件中添加下面的聲明來(lái)代替:

<web-app>
    ...
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    ...
</web-app>

????????如果你的監(jiān)聽(tīng)器設(shè)置有問(wèn)題,作為一種選擇,你可以考慮Spring的RequestContextFilter。過(guò)濾器映射依賴(lài)于web應(yīng)用程序的相關(guān)配置,因此你必須適當(dāng)?shù)母乃?/p>

<web-app>
    ...
    <filter>
        <filter-name>requestContextFilter</filter-name>
        <filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>requestContextFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    ...
</web-app>

????????DispatcherServlet,RequestContextListenerRequestContextFilter都是在做同樣的事,也就是說(shuō)將HTTP請(qǐng)求對(duì)象綁定到服務(wù)請(qǐng)求的Thread上。這使得request作用域和session作用域的beans在更深一層的調(diào)用鏈中是可用的。

Request作用域

考慮下面的bean定義的XML配置:

<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>

????????對(duì)于每一個(gè)HTTP請(qǐng)求,Spring容器通過(guò)使用loginAction定義創(chuàng)建一個(gè)新的LoginAction bean實(shí)例。也就是說(shuō),loginAction bean的作用域是在HTTP請(qǐng)求級(jí)別的。你可以任意改變創(chuàng)建的實(shí)例的內(nèi)部狀態(tài),因?yàn)槠渌母鶕?jù)loginAction bean定義創(chuàng)建的實(shí)例不會(huì)看到這些狀態(tài)的改變;它們對(duì)于每個(gè)單獨(dú)的請(qǐng)求都是獨(dú)有的。當(dāng)請(qǐng)求處理完成時(shí),請(qǐng)求作用域的bean被丟棄。

????????當(dāng)使用注解驅(qū)動(dòng)的組件或Java配置時(shí),@RequestScope注解能用來(lái)指定一個(gè)組件的作用域?yàn)閞equest。

@RequestScope
@Component
public class LoginAction {
    // ...
}

Session作用域

????????考慮下面的bean定義的XML配置:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

????????對(duì)于單個(gè)HTTP Session的生命周期,Spring容器通過(guò)userPreferences bean定義創(chuàng)建一個(gè)UserPreferences bean實(shí)例。換句話(huà)說(shuō),userPreferences bean的有效作用域是HTTP Session級(jí)別的。正如request作用域的beans一樣,你可以任意改變你想改變的創(chuàng)建的bean實(shí)例的內(nèi)部狀態(tài),知道其它的使用根據(jù)userPreferences bean定義創(chuàng)建的HTTP Session實(shí)例也不會(huì)看到這些內(nèi)部狀態(tài)的改變,因?yàn)樗鼈儗?duì)于每個(gè)單獨(dú)的HTTP Session都是獨(dú)有的。當(dāng)HTTP Session被最終銷(xiāo)毀時(shí),Session作用域的bean也被銷(xiāo)毀。

????????當(dāng)使用注解驅(qū)動(dòng)的組件或Java配置時(shí),@SessionScope注解能用來(lái)指定一個(gè)組件的作用域?yàn)閟ession。

@SessionScope
@Component
public class UserPreferences {
    // ...
}

Application作用域

????????考慮下面的bean定義的XML配置:

<bean id="appPreferences" class="com.foo.AppPreferences" scope="application"/>

????????對(duì)于整個(gè)web應(yīng)用而言,Spring容器根據(jù)appPreferences bean定義只創(chuàng)建一次AppPreferences bean的新實(shí)例。也就是說(shuō),appPreferences bean的作用域是ServletContext級(jí)別的,作為一個(gè)正規(guī)的ServletContext特性來(lái)存儲(chǔ)。這有點(diǎn)類(lèi)似于Spring的單例bean,但在兩個(gè)方面是不同的:它對(duì)于每個(gè)ServletContext是單例的,而不是每個(gè)Spring ApplicationContext(在任何給定的web應(yīng)用中可能有幾個(gè)ApplicationContext),它是真正顯露的,因此作為一個(gè)ServletContext特性是可見(jiàn)的。

????????當(dāng)使用注解驅(qū)動(dòng)的組件或Java配置時(shí),@ApplicationScope注解能用來(lái)指定一個(gè)組件的作用域?yàn)锳pplication。

@ApplicationScope
@Component
public class AppPreferences {
    // ...
}

具有作用域的bean作為依賴(lài)項(xiàng)

????????Spring IoC容器不僅管理對(duì)象的實(shí)例化,而且管理協(xié)作者(或依賴(lài))的綁定。例如,如果你想將一個(gè)具有HTTP request作用域的bean注入到另一個(gè)具有更長(zhǎng)生命周期作用域的bean中,你可能選擇注入一個(gè)AOP代理來(lái)代替具有作用域的bean。也就是說(shuō),你需要注入一個(gè)代理對(duì)象,這個(gè)對(duì)象能顯露與具有作用域的對(duì)象相同的接口,但也能從相關(guān)的作用域中(例如HTTP request作用域)得到真正的目標(biāo)對(duì)象,能通過(guò)委派方法調(diào)用到真正的對(duì)象。

你也可以在作用域?yàn)?code>singleton的beans之間使用<aop:scoped-proxy/>,將通過(guò)中間代理的引用進(jìn)行序列化,因此能通過(guò)反序列化重新獲得目標(biāo)的單例bean。

當(dāng)將作用域?yàn)?code>prototype的bean聲明為<aop:scoped-proxy/>時(shí),每個(gè)在共享代理上的方法調(diào)用會(huì)引起一個(gè)新目標(biāo)實(shí)例(調(diào)用朝向的)的創(chuàng)建。

通過(guò)生命周期安全的方式訪(fǎng)問(wèn)更短的作用域中beans,作用域代理也不是唯一的方式。你也可以簡(jiǎn)單的聲明你的注入點(diǎn)(例如,構(gòu)造函數(shù)/setter參數(shù)或自動(dòng)裝配領(lǐng)域)為ObjectFactory<MyTargetBean>,考慮到每次需要的時(shí)候通過(guò)getObject()調(diào)用來(lái)取得索要的當(dāng)前實(shí)例——沒(méi)有分別控制實(shí)例或儲(chǔ)存它。

JSR-300變量被稱(chēng)作Provider,對(duì)于每一次取回嘗試使用Provider<MyTargetBean>聲明和對(duì)應(yīng)的get()調(diào)用。關(guān)于JSR-330整體的更多細(xì)節(jié)請(qǐng)看這兒

????????下面例子中的配置只有一行,但對(duì)于理解它背后的"why"和"how"是重要的。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- an HTTP Session-scoped bean exposed as a proxy -->
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
        <!-- instructs the container to proxy the surrounding bean -->
        <aop:scoped-proxy/>
    </bean>

    <!-- a singleton-scoped bean injected with a proxy to the above bean -->
    <bean id="userService" class="com.foo.SimpleUserService">
        <!-- a reference to the proxied userPreferences bean -->
        <property name="userPreferences" ref="userPreferences"/>
    </bean>
</beans>

????????為了創(chuàng)建這樣一個(gè)代理,你插入一個(gè)子元素<aop:scoped-proxy/>到具有作用域的bean定義中(看"選擇創(chuàng)建的代理類(lèi)型"小節(jié)和38章,基于XML Schema的配置)。為什么bean定義的作用域?yàn)?code>request,session和定制作用域級(jí)別需要<aop:scoped-proxy/>元素?讓我們檢查下面的單例bean定義,并將它與你需要定義的前面提到的作用域進(jìn)行比較(注意下面的userPreferences bean定義按目前情況是不完全的)。

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

????????在上面的例子中,單例bean userManager通過(guò)引用被注入到具有HTTP Session作用域的bean userPreferences中。這的突出點(diǎn)是userManager bean是單例:每個(gè)容器它將確定的被實(shí)例化一次,它的依賴(lài)(在這個(gè)例子中只有一個(gè),userPreferences bean)也只注入一次。這意味著userManager bean只能對(duì)確定的同一個(gè)userPreferences對(duì)象進(jìn)行操作,也就是最初注入的那個(gè)對(duì)象。

????????當(dāng)將一個(gè)短期作用域的bean注入到一個(gè)長(zhǎng)期作用域的bean中時(shí),這不是你想要的行為,例如將一個(gè)具有HTTP Session作用域的協(xié)作bean作為一個(gè)依賴(lài)注入到一個(gè)單例bean中。當(dāng)然,你需要一個(gè)單一的userManager對(duì)象,對(duì)于HTTP Session的生命周期,你需要一個(gè)特定的被稱(chēng)為HTTP SessionuserPreferences對(duì)象。因此容器創(chuàng)建了一個(gè)與UserPreferences類(lèi)暴露相同的公共接口的對(duì)象(理想情況下是一個(gè)UserPreferences實(shí)例),這個(gè)對(duì)象能從作用域機(jī)制中(HTTP request,Session等)取得真正的UserPreferences對(duì)象。容器將這個(gè)代理對(duì)象注入到userManager bean中,userManager bean不會(huì)意識(shí)到UserPreferences引用是一個(gè)代理。在這個(gè)例子中,當(dāng)UserManager實(shí)例調(diào)用依賴(lài)注入的UserPreferences對(duì)象的方法時(shí),它實(shí)際上調(diào)用的是代理中的一個(gè)方法。代理能從HTTP Session中(在這個(gè)例子)取得真正的UserPreferences對(duì)象,將方法調(diào)用委托到取得的真正的UserPreferences對(duì)象上。

????????因此當(dāng)注入具有request或session作用域的bean到協(xié)作對(duì)象中時(shí),你需要下面的,正確的,完整的配置:

<bean id="userPreferences" class="com.foo.UserPreferences" scope="session">
    <aop:scoped-proxy/>
</bean>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

選擇創(chuàng)建的代理類(lèi)型

????????當(dāng)Spring容器為具有<aop:scoped-proxy/>標(biāo)記的bean創(chuàng)建代理時(shí),默認(rèn)情況下,創(chuàng)建一個(gè)基于CGLIB的類(lèi)代理。

CGLIB代理只攔截公有方法調(diào)用。在這個(gè)代理上不調(diào)用非公有方法;它們不能委托給實(shí)際作用域目標(biāo)對(duì)象。

????????作為一種選擇,對(duì)于這種具有作用域的bean你可以配置Spring容器創(chuàng)建標(biāo)準(zhǔn)JDK基于接口的代理,通過(guò)指定<aop:scoped-proxy/>元素的proxy-target-class特定的值為false。使用JDK基于接口的代理意味著在你應(yīng)用程序類(lèi)路徑中你不需要額外的庫(kù)來(lái)支持這種代理的使用。然而,它也意味著具有作用域的bean的類(lèi)必須實(shí)現(xiàn)至少一個(gè)接口,并且注入這個(gè)bean的所有協(xié)作者必須通過(guò)它接口中的一個(gè)來(lái)引用它。

<!-- DefaultUserPreferences implements the UserPreferences interface -->
<bean id="userPreferences" class="com.foo.DefaultUserPreferences" scope="session">
    <aop:scoped-proxy proxy-target-class="false"/>
</bean>

<bean id="userManager" class="com.foo.UserManager">
    <property name="userPreferences" ref="userPreferences"/>
</bean>

????????關(guān)于選擇基于類(lèi)或基于接口代理的更多細(xì)節(jié)信心,請(qǐng)看7.6小節(jié),"代理機(jī)制"。

3.5.5 定制作用域

????????bean作用域機(jī)制是可擴(kuò)展的;你可以定義你自己的作用域,甚至重新定義現(xiàn)有的作用域,雖然后者被認(rèn)為是一種不好的實(shí)踐,你不能覆蓋內(nèi)置的singleton作用域和prototype作用域。

創(chuàng)建一個(gè)定制作用域

????????為了將你的定制作用域集成到Spring容器中,你需要實(shí)現(xiàn)org.springframework.beans.factory.config.Scope接口,這一節(jié)將描述這個(gè)接口。對(duì)于怎樣實(shí)現(xiàn)你自己作用域的想法,請(qǐng)看Spring框架本身提供的Scope實(shí)現(xiàn)和Scope文檔,它們解釋了你需要實(shí)現(xiàn)的方法的更多細(xì)節(jié)。

????????Scope接口有四個(gè)方法,從作用域中取得對(duì)象,從作用域中移除對(duì)象,并且允許它們被銷(xiāo)毀。

????????下面的方法從潛在的作用域返回對(duì)象。session作用域?qū)崿F(xiàn),例如,返回具有session作用域的bean(如果它不存在,這個(gè)方法返回一個(gè)bean的新實(shí)例,然后綁定到session中準(zhǔn)備將來(lái)引用)。

Object get(String name, ObjectFactory objectFactory)

????????下面的方法從潛在作用域中移除對(duì)象。以session作用域?qū)崿F(xiàn)為例,從潛在的session中移除session作用域的bean。對(duì)象應(yīng)該被返回,但如果沒(méi)有找到指定名字的對(duì)象會(huì)返回空。

Object remove(String name)

????????下面的方法是注冊(cè)當(dāng)作用域銷(xiāo)毀時(shí)或當(dāng)作用域中的指定對(duì)象銷(xiāo)毀時(shí),作用域應(yīng)該執(zhí)行的回調(diào)函數(shù)。銷(xiāo)毀回調(diào)函數(shù)的更多信息請(qǐng)看文檔或Spring作用域?qū)崿F(xiàn)。

void registerDestructionCallback(String name, Runnable destructionCallback)

????????下面的方法是獲得潛在作用域的會(huì)話(huà)標(biāo)識(shí)符。每個(gè)作用域的標(biāo)識(shí)符都是不同的。對(duì)于session作用域?qū)崿F(xiàn),標(biāo)識(shí)符是session標(biāo)識(shí)符。

String getConversationId()

使用定制作用域

????????在你編寫(xiě)和測(cè)試一個(gè)或多個(gè)定制Scope實(shí)現(xiàn)之后,你需要讓Spring容器感知到你的新作用域。下面是在Spring容器中注冊(cè)一個(gè)新Scope的主要方法:

void registerScope(String scopeName, Scope scope);

????????這個(gè)方法是在ConfigurableBeanFactory接口中聲明的,在大多數(shù)具體的ApplicationContext實(shí)現(xiàn)中都可獲得,在Spring中通過(guò)BeanFactory屬性得到。

????????registerScope(..)方法中的第一個(gè)參數(shù)是關(guān)于作用域的唯一名字;Spring容器本身中的這種名字的例子是singletonprototype。registerScope(..)方法中的第二個(gè)參數(shù)是你想注冊(cè)和使用的定制Scope實(shí)現(xiàn)的真正實(shí)例。

????????假設(shè)你編寫(xiě)了你的定制Scope實(shí)現(xiàn)并按如下注冊(cè)。

下面的例子使用Spring包含的SimpleThreadScope,但默認(rèn)是不注冊(cè)的。這個(gè)用法說(shuō)明與你自己的定制Scope是一樣的。

Scope threadScope = new SimpleThreadScope();
beanFactory.registerScope("thread", threadScope);

????????然后創(chuàng)建具有你自己定制的Scope規(guī)則的bean定義:

<bean id="..." class="..." scope="thread">

????????在定制Scope實(shí)現(xiàn)后,你不會(huì)受限于作用域的程序注冊(cè)。你也可以聲明式的進(jìn)行Scope注冊(cè),使用CustomScopeConfigurer類(lèi):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean class="org.springframework.beans.factory.config.CustomScopeConfigurer">
        <property name="scopes">
            <map>
                <entry key="thread">
                    <bean class="org.springframework.context.support.SimpleThreadScope"/>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="bar" class="x.y.Bar" scope="thread">
        <property name="name" value="Rick"/>
        <aop:scoped-proxy/>
    </bean>

    <bean id="foo" class="x.y.Foo">
        <property name="bar" ref="bar"/>
    </bean>

</beans>

當(dāng)你在FactoryBean實(shí)現(xiàn)中放入<aop:scoped-proxy/>時(shí),它是工廠(chǎng)bean本身具有作用域,不是從getObject()中返回的對(duì)象。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容