spring詳解(二)

容器中bean的作用域

|作用域|描述|
|---|---|
|singleton|單例模式,在整個(gè)Spring IoC容器中,使用singleton定義的bean將只有一個(gè)實(shí)例|
|prototype|原型模式,每次通過(guò)容器的getBean方法獲取prototype定義的Bean時(shí),都將產(chǎn)生一個(gè)新實(shí)例|
|request|對(duì)于每次HTTP請(qǐng)求中,使用request定義的bean都將產(chǎn)生一個(gè)新實(shí)例,只有在web應(yīng)用程序使用Spring時(shí),該作用域才有效|
|session|同理|
|global session|同理|

注意request和session作用域只在web應(yīng)用中才生效,并且必須在web應(yīng)用中增加額外的配置才會(huì)生效,為了讓request,session兩個(gè)作用域生效,必須將HTTP請(qǐng)求對(duì)象綁定到為該請(qǐng)求提供服務(wù)的線(xiàn)程上,這使得具有request和session作用域的Bean實(shí)例能夠在后面的調(diào)用鏈中被訪(fǎng)問(wèn)。

當(dāng)支持Servlet2.4及以上規(guī)范的web容器時(shí),我們可以在web應(yīng)用的web.xml增加如下Listener配置,該Listener負(fù)責(zé)為request作用域生效:

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

 如果僅使用了支持Servlet2.4以前規(guī)范的web容器,則該容器不支持Listener規(guī)范,故無(wú)法使用這種配置,可以使用Filter配置方式,我們可以在web應(yīng)用的web.xml增加如下Filter配置:

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

再如下面的代碼:

<bean id="p" class="lee.Person" scope="request"/>

`這樣容器就會(huì)為每次HTTP請(qǐng)求生成一個(gè)lee.Person的實(shí)例當(dāng)該請(qǐng)求響應(yīng)結(jié)束時(shí),該實(shí)例也隨之消失。`
`如果Web應(yīng)用直接使用Spring MVC作為MVC框架,即使用`SpringDispatchServlet`或`DispatchPortlet`來(lái)攔截所有用戶(hù)請(qǐng)求,則`無(wú)需這些額外的配置`,`因?yàn)镾pringDispatchServlet或DispatchPortlet已經(jīng)處理了所有和請(qǐng)求有關(guān)的狀態(tài)處理`。`

④**獲取容器的引用**:

>`通常情況下:`
Bean無(wú)需訪(fǎng)問(wèn)Spring容器,而是通過(guò)Spring容器訪(fǎng)問(wèn)的,即使 需要手動(dòng)訪(fǎng)問(wèn)Spring容器,程序也已通過(guò)類(lèi)似下面的代碼獲取Spring容器 的引用。

ApllicationContext cts = ClassPathApplalicationContext("bean.xml");

`但在一些極端的情況下`,可能Bean需要訪(fǎng)問(wèn)Spring容器。Spring提供另一種方法訪(fǎng)問(wèn)Spring容器:

>實(shí)現(xiàn)BeanFactoryAware接口的Bean,擁有訪(fǎng)問(wèn)Spring容器的能力,實(shí)現(xiàn)BeanFactoryAware的Bean被容器實(shí)例化后,會(huì)擁有一個(gè)引用指向創(chuàng)建他的BeanFactory。BeanFactoryAware只有一個(gè)方法setBeanFactory(BeanFactory beanFactory)該參數(shù)指向創(chuàng)建他的BeanFactory。

>`缺點(diǎn)`:污染了代碼,使代碼與Spring接口耦合在一起,因此沒(méi)有特別的必要,建議不要直接訪(fǎng)問(wèn)容器。

---
4.**Bean實(shí)例的創(chuàng)建方式及對(duì)應(yīng)配置**:

>創(chuàng)建Bean的方法:
<li>調(diào)用構(gòu)造器創(chuàng)建Bean實(shí)例;
<li>調(diào)用靜態(tài)工廠(chǎng)方法創(chuàng)建Bean;
<li>調(diào)用實(shí)例工廠(chǎng)創(chuàng)建Bean。

**調(diào)用靜態(tài)工廠(chǎng)方法創(chuàng)建Bean**:

>使用靜態(tài)工廠(chǎng)方法創(chuàng)建Bean實(shí)例時(shí),class屬性也必須指定,但此時(shí)class屬性并不是指定Bean實(shí)例的實(shí)現(xiàn)類(lèi),而是靜態(tài)工廠(chǎng)類(lèi)。因?yàn)镾pring需要知道是用哪個(gè)工廠(chǎng)來(lái)創(chuàng)建Bean實(shí)例。另外,還需要使用factory-method來(lái)指定靜態(tài)工廠(chǎng)方法名,Spring將調(diào)用靜態(tài)工廠(chǎng)方法(可能包含一組參數(shù)),來(lái)返回一個(gè)Bean實(shí)例,一旦獲得了指定Bean實(shí)例,Spring后面的處理步驟與采用普通方法創(chuàng)建Bean實(shí)例則完全一樣。需要注意的是,當(dāng)使用靜態(tài)工廠(chǎng)方法來(lái)創(chuàng)建Bean時(shí),這個(gè)factory-method必須要是靜態(tài)的。這段闡述聽(tīng)上去有點(diǎn)暈,話(huà)不多說(shuō),上代碼:
`先定義一個(gè)接口,靜態(tài)方法產(chǎn)生的將是該接口的實(shí)例:`

public interface Animal {
public void sayHello();
}

`下面是接口的兩個(gè)實(shí)現(xiàn)類(lèi):`

public class Cat implements Animal {
private String msg;
//依賴(lài)注入時(shí)必須的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",喵");
}
}

public class Dog implements Animal {
private String msg;
//依賴(lài)注入時(shí)必須的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + ",旺");
}
}

`下面的AnimalFactory工廠(chǎng)中包含了一個(gè)getAnimal的靜態(tài)方法,該方法將根據(jù)傳入的參數(shù)決定創(chuàng)建哪個(gè)對(duì)象。這是`典型的靜態(tài)工廠(chǎng)設(shè)計(jì)模式`。`

public class AnimalFactory {
public static Animal getAnimal(String type){
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}

`如果需要指定Spring使用AnimalFactory來(lái)產(chǎn)生Animal對(duì)象,則可在Spring配置文件中作如下配置:`


<bean id="cat" class="com.abc.AnimalFactory" factory-method="getAnimal">

<constructor-arg value="cat" />

<property name="msg" value="貓貓" />
</bean>

<bean id="dog" class="com.abc.AnimalFactory" factory-method="getAnimal">

<constructor-arg value="dog" />

<property name="msg" value="狗狗" />
</bean>

`從上面的配置可以看出:cat和dog兩個(gè)Bean配置的class和factory-method完全相同,這是因?yàn)閮蓚€(gè)實(shí)例都使用同一個(gè)靜態(tài)工廠(chǎng)類(lèi)、同一個(gè)靜態(tài)工廠(chǎng)方法產(chǎn)生得到的。只是為這個(gè)靜態(tài)工廠(chǎng)方法指定的參數(shù)不同,使用<constructor-arg />元素來(lái)為靜態(tài)工廠(chǎng)方法指定參數(shù)。`
主程序獲取cat和dog兩個(gè)Bean實(shí)例的方法不變,同樣只需要調(diào)用Spring容器的getBean()即可:

public class Test {
public static void main(String args[]){
ApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
Animal a1 = context.getBean("cat", Animal.class);
a1.sayHello();
Animal a2 = context.getBean("dog", Animal.class);
a2.sayHello();
}
}

輸出結(jié)果:

貓貓,喵
狗狗,旺

使用靜態(tài)工廠(chǎng)方法創(chuàng)建實(shí)例時(shí)必須提供工廠(chǎng)類(lèi)和產(chǎn)生實(shí)例的靜態(tài)工廠(chǎng)方法。通過(guò)靜態(tài)工廠(chǎng)方法創(chuàng)建實(shí)例時(shí)需要對(duì)Spring配置文件做如下改變:
<li>`class屬性不在是Bean實(shí)例的實(shí)現(xiàn)類(lèi),而是生成Bean實(shí)例的靜態(tài)工廠(chǎng)類(lèi)`

><li>`使用factory-method指定生產(chǎn)Bean實(shí)例的靜態(tài)工廠(chǎng)方法`

><li>`如果靜態(tài)工廠(chǎng)方法需要參數(shù),使用<constructor-arg />元素為其配置`
`當(dāng)我們指定Spring使用靜態(tài)工廠(chǎng)方法來(lái)創(chuàng)建Bean實(shí)例時(shí),Spring將`先解析配置文件`,并根據(jù)配置文件指定的信息,通過(guò)`反射調(diào)用靜態(tài)工廠(chǎng)類(lèi)的靜態(tài)工廠(chǎng)方法`,并將該靜態(tài)工廠(chǎng)方法的返回值作為Bean實(shí)例,在這個(gè)過(guò)程中,`Spring不再負(fù)責(zé)創(chuàng)建Bean實(shí)例`,Bean實(shí)例是由用戶(hù)提供的靜態(tài)工廠(chǎng)方法提供的。`

---
**調(diào)用實(shí)例工廠(chǎng)方法創(chuàng)建Bean**:

>實(shí)例工廠(chǎng)方法與靜態(tài)工廠(chǎng)方法只有一點(diǎn)不同:調(diào)用靜態(tài)工廠(chǎng)方法只需要使用工廠(chǎng)類(lèi)即可,調(diào)用實(shí)例工廠(chǎng)方法則必須使用工廠(chǎng)實(shí)例。所以在Spring配置上也只有一點(diǎn)區(qū)別:配置靜態(tài)工廠(chǎng)方法指定靜態(tài)工廠(chǎng)類(lèi),配置實(shí)例工廠(chǎng)方法則指定工廠(chǎng)實(shí)例。
`同樣是上面的例子將AnimalFactory修改為:`

public clas AnimalFactory {
public Animal getAnimal(String type){ //這里僅僅是去掉了static關(guān)鍵字
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}

`Spring文件修改為:`


<bean id="animalFactory" class="com.abc.AnimalFactory" />

<bean id="cat" factory-bean="animalFactory" factory-method="getAnimal">

<constructor-arg value="cat" />
<property name="msg" value="貓貓" />
</bean>
<bean id="dog" factory-bean="animalFactory" factory-method="getAnimal">
<constructor-arg value="dog" />
<property name="msg" value="狗狗" />
</bean>

測(cè)試類(lèi)不用修改,輸出結(jié)果和上面相同。

---

最后編輯于
?著作權(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)容