欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解讀Spring?Bean的作用域

 更新時間:2022年10月31日 09:17:47   作者:kongmin_123  
這篇文章主要介紹了解讀Spring?Bean的作用域,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教

在Spring中,bean作用域用于確定哪種類型的bean實(shí)例應(yīng)該從Spring容器中返回給調(diào)用者。

目前Spring Bean的作用域或者說范圍主要有五種

作用域描述
singleton在spring IoC容器僅存在一個Bean實(shí)例,Bean以單例方式存在,bean作用域范圍的默認(rèn)值。
prototype每次從容器中調(diào)用Bean時,都返回一個新的實(shí)例,即每次調(diào)用getBean()時,相當(dāng)于執(zhí)行newXxxBean()。
request每次HTTP請求都會創(chuàng)建一個新的Bean,該作用域僅適用于web的Spring WebApplicationContext環(huán)境。
session同一個HTTP Session共享一個Bean,不同Session使用不同的Bean。該作用域僅適用于web的Spring WebApplicationContext環(huán)境。
application限定一個Bean的作用域?yàn)镾ervletContext的生命周期。該作用域僅適用于web的Spring WebApplicationContext環(huán)境。

(1)被聲明為singleton的bean

如果bean的作用域的屬性被聲明為singleton,那么Spring Ioc容器只會創(chuàng)建一個共享的bean實(shí)例。對于所有的bean請求,只要id與該bean定義的相匹配,那么Spring在每次需要時都返回同一個bean實(shí)例。

Singleton是單例類型,就是在創(chuàng)建起容器時就同時自動創(chuàng)建了一個bean的對象,不管你是否使用,他都存在了,每次獲取到的對象都是同一個對象。注意,singleton作用域是Spring中的缺省作用域。你可以在 bean 的配置文件中設(shè)置作用域的屬性為 singleton,如下所示:

<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
? ? <!-- collaborators and configuration for this bean go here -->
</bean>

單例的例子

1.首先創(chuàng)建一個bean。

package com.spring.demo;
public class ?SingletonBean{
? ?private String message;
? ?public void setMessage(String message){
? ? ? this.message ?= message;
? ?}
? ?public void getMessage(){
? ? ? System.out.println("Your Message : " + message);
? ?}
}

2.在Spring的配置文件中配置該bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
? ? ? ?xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
? ? ? ?xsi:schemaLocation="
? ? ? ? http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
?
? ? <bean id="SingletonBean" class="com.spring.demo.SingletonBean" scope="singleton"></bean>
? ? <!-- 或者 -->
? ? <!-- ?<bean id="SingletonBean" class="com.spring.demo.SingletonBean" ></bean> -->
</beans>

測試該Bean是否為單例的。

package com.spring.demo;
?
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.junit.Test;
?
public class TestBean {
?
? ? @Test
? ? public void textUser()
? ? {
? ? ? ? //1.獲取spring文件
? ? ? ? ApplicationContext context = new ClassPathXmlApplicationContext("Bean.xml");
? ? ? ? //2.由配置文件返回對象
? ? ? ? SingletonBean singletonBeanA = (SingletonBean)context.getBean("SingletonBean");
? ? ? ? singletonBeanA.setMessage("I'm object A");
? ? ? ? singletonBeanA.getMessage();
? ? ? ? SingletonBean singletonBeanB = (SingletonBean)context.getBean("SingletonBean");
? ? ? ? singletonBeanB.getMessage();
? ? }
}

運(yùn)行結(jié)果:

由于SingletonBean是單例的作用域,創(chuàng)建兩個SingletonBean對象,第二個對象獲取SingletonBean對象中的消息值得時候即使是由一個新的getBean()方法來獲取,也可以不用設(shè)置對象中消息的值就可以直接獲取SingletonBean中的消息,因?yàn)檫@時的消息已經(jīng)由第一個對象初始化了。

在單例中,每個Spring IoC容器只有一個實(shí)例,無論創(chuàng)建多少個對象,調(diào)用多少次getMessafe( )方法獲取它,它總是返回同一個實(shí)例。 

(2)被聲明為prototype的bean

當(dāng)一個bean的作用域?yàn)閜rototype,表示一個bean定義對應(yīng)多個對象實(shí)例。

聲明為prototype作用域的bean會導(dǎo)致在每次對該bean請求(將其注入到另一個bean中,或者以程序的方式調(diào)用容器的getBean()方法)時都會創(chuàng)建一個新的bean實(shí)例。

prototype是原型類型,它在我們創(chuàng)建容器的時候并沒有實(shí)例化,而是當(dāng)我們獲取bean的時候才會去創(chuàng)建一個對象,而且我們每次獲取到的對象都不是同一個對象。

根據(jù)經(jīng)驗(yàn),對有狀態(tài)的bean應(yīng)該使用prototype作用域,而對無狀態(tài)的bean則應(yīng)該使用singleton作用域。

prototype的例子。

還是上面的代碼。其他代碼不變,把Bean.xml文件中bean的作用域由singleton改為prototype。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
 
    <bean id="SingletonBean" class="com.spring.demo.SingletonBean" scope="prototype"></bean>
   
</beans>

執(zhí)行代碼,程序的執(zhí)行結(jié)果為:

從圖上可以看出在SingletonBeanA中設(shè)置的參數(shù)值在SingletonBeanB就獲取不到了,說明這兩個對象現(xiàn)在返回的就不是同一個對象實(shí)例。

(3)使用注解定義 bean 的作用域

除了在Bean.xml文件中定義bean的作用域之外,還可以使用注解來定義 bean 的作用域。

1.在Bean中加上注解。

package com.spring.demo;
 
import org.springframework.context.annotation.Scope;;
import org.springframework.stereotype.Component;
 
@Component("SingletonBean")
@Scope("prototype")
public class SingletonBean {
    private String message;
    public void setMessage(String message){
        this.message  = message;
    }
    public void getMessage(){
        System.out.println("Your Message : " + message);
    }
}
  • @Component("SingletonBean")注解是告訴Spring這是一個bean。
  • @Scope("prototype")注解是告訴Spring該bean的作用域是prototype。

2.bean.xml文件修改一下。

<?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/context
	http://www.springframework.org/schema/context/spring-context-4.2.xsd">
   
    <context:component-scan base-package="com.spring.demo" />
 
</beans>

<context:component-scan base-package="com.spring.demo" />就是掃描com.spring.demo包中的所有類的注解。

測試代碼不用變,運(yùn)行測試。

和在bean.xml中直接定義bean和其作用域是一樣的效果。其他作用域也可以使用注解方式聲明bean的作用域。

request,session和application這三個作用域都是基于web的Spring WebApplicationContext實(shí)現(xiàn)的,只有在web環(huán)境下(比如XmlWebApplicationContext)中才能使用。 如果開發(fā)者僅僅在常規(guī)的Spring IoC容器中比如ClassPathXmlApplicationContext在中使用這些作用域,那么將會拋出一個IllegalStateException來說明使用了未知的作用域。

也就是當(dāng)用戶使用Spring的WebApplicationContext時,除了使用常規(guī)的singleton和prototype作用域之外,還可以使用另外3種Bean的作用域,即request,session和application。

在使用Web應(yīng)用環(huán)境相關(guān)的Bean作用域時,必須在Web容器中進(jìn)行一些額外的配置:

1.如果開發(fā)者使用了Spring Web MVC框架的話,每一個請求都會通過Spring的DispatcherServlet來處理,也就沒有其他特殊的初始化配置,就不需要配置了。DispatcherServlet已經(jīng)包含了相關(guān)的狀態(tài)。

2.如果開發(fā)者使用的是低版本W(wǎng)eb容器比如Servlet 2.5的web容器,請求不是通過Spring的DispatcherServlet(比如JSF或者Struts)來處理的。那么開發(fā)者需要注冊org.springframework.web.context.request.RequestContextListener或者ServletRequestListener??梢栽趙eb.xml中增加如下的Listener聲明: 

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

ServletContextListener只負(fù)責(zé)監(jiān)聽web容器啟動和關(guān)閉的事件,而RequestContextListener實(shí)現(xiàn)了ServletRequestListener監(jiān)聽器接口,該監(jiān)聽器監(jiān)聽http請求事件。Web服務(wù)器接收到的每一次請求都會通知該監(jiān)聽器。 

而在Servlet 3.0以后,這些都能夠通過WebApplicationInitializer接口來實(shí)現(xiàn)配置。

3.如果不使用Listener,也可以考慮使用Spring的RequestContextFilter,通過http過濾器進(jìn)行配置,在url-pattern中對所有的頁面進(jìn)行過濾。也是在web.xml中進(jìn)行配置。

<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>

配置完這些額外的配置之后,就可以使用另外的3種bean的作用域了。 

(4)請求作用域

請求作用域參考如下的Bean定義

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

Spring容器會在每次用到loginAction來處理每個HTTP請求的時候都會創(chuàng)建一個新的LoginAction實(shí)例。也就是說,loginActionBean的作用域是HTTP Request級別的。 

當(dāng)http請求調(diào)用作用域?yàn)閞equest的bean的時候,每增加一個HTTP請求,Spring就會創(chuàng)建一個新的bean,在請求處理完成之后便及時銷毀這個bean。

開發(fā)者可以隨意改變實(shí)例的狀態(tài),因?yàn)橥ㄟ^loginAction請求來創(chuàng)建的其他實(shí)例根本看不到開發(fā)者改變的實(shí)例狀態(tài),所有創(chuàng)建的Bean實(shí)例都是根據(jù)獨(dú)立的請求來的。

(5)會話作用域

會話作用域參考如下的Bean定義

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

Spring容器會在每次調(diào)用到userPreferences時,在一個單獨(dú)的HTTP會話周期來創(chuàng)建一個新的UserPreferences實(shí)例。換言之,userPreferencesBean的作用域是HTTP Session級別的。

Session中所有http請求共享同一個請求的bean實(shí)例。Session結(jié)束后就銷毀bean。 在request-scoped作用域的Bean上,開發(fā)者可以隨意的更改實(shí)例的狀態(tài)。同樣,使用從同一個userPreferences bean定義創(chuàng)建的其他HTTP Session實(shí)例在看不到不是自己的內(nèi)部狀態(tài)的修改,因?yàn)樗麄兪菃蝹€的HTTP會話。

每個Session請求都會創(chuàng)建新的userPreferences實(shí)例,所以開發(fā)者更改一個Bean的狀態(tài),對于其他的Bean仍然是不可見的。

(6)全局作用域

全局作用域參考如下的Bean定義

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

Spring容器會在整個web應(yīng)用范圍使用到appPreferences的時候創(chuàng)建一個新的AppPreferences的實(shí)例。也就是說,appPreferencesBean是在ServletContext級別的,作為常規(guī)的ServletContext屬性。這種作用域在一些程度上來說和Spring的單例作用域相似,但是也有如下不同之處:

1.application作用域是每個ServletContext中包含一個,而不是每個SpringApplicationContext之中包含一個(某些應(yīng)用中可能包含不止一個ApplicationContext)。

2.application作用域僅僅作為ServletContext的屬性可見,單例Bean是ApplicationContext可見。

接下來再來簡單的學(xué)習(xí)下在Spring當(dāng)中如何自定義作用域:

在Spring 2.0中,Spring的Bean作用域機(jī)制是可以擴(kuò)展的,這意味著,你不僅可以使用Spring提供的預(yù)定義Bean作用域,還可以定義自己的作用域,甚至重新定義現(xiàn)有的作用域(不提倡這么做,而且你不能覆蓋內(nèi)置的singleton和prototype作用域)

(7)自定義作用域

除了使用Spring已經(jīng)定義好的作用域之外,還可以自定義bean的作用域。

要底線自定義作用域

1.首先需要實(shí)現(xiàn)自定義Scope類。

首先要先實(shí)現(xiàn)org.springframework.beans.factory.config.Scope這個接口,要將自定義scope集成到Spring容器當(dāng)中就必須要實(shí)現(xiàn)這個接口。接口中有兩個常用的方法,分別用于底層存儲機(jī)制獲取和刪除這個對象。

2.在實(shí)現(xiàn)一個或多個自定義Scope并測試通過之后,接下來便是如何讓Spring容器來識別新的作用域。registerScope方法就是在Spring容器中用來注冊新的作用域。

void registerScope(String scopeName, Scope scope);

其中:第一個參數(shù)是與作用域相關(guān)的全局唯一的名稱,第二個參數(shù)是準(zhǔn)備實(shí)現(xiàn)的作用域的實(shí)例,就是實(shí)現(xiàn)Scope接口的實(shí)例。

比如實(shí)現(xiàn)Scope接口的類為SimpleThreadScope,要實(shí)現(xiàn)的自定義的bean的作用域的名稱為“thread”,那就可以這么寫。

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

3.在實(shí)現(xiàn)和注冊自定義的scope類之后,就可以通過如下類似的Bean定義來使用自定義的Scope:

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

另外,在自定義的Scope中,開發(fā)者也不限于僅僅通過編程方式來實(shí)現(xiàn)自定義的bean的作用域,也可以在Spring的配置文件中配置和使用自定義作用域和,比如配置CustomScopeConfigurer實(shí)例實(shí)現(xiàn)自定義的作用域,聲明作用域名稱為“thread”,就可以在xml文件中做如下類似的定義。

<?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>

以上就是Spring Bean作用域的一些基本信息。僅為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論