③容器中bean的作用域:
|作用域|描述|
|---|---|
|singleton
|單例模式各淀,在整個Spring IoC容器中,使用singleton定義的bean將只有一個實例
|
|prototype
|原型模式诡挂,每次通過容器的getBean方法獲取prototype定義的Bean時碎浇,都將產(chǎn)生一個新實例
|
|request
|對于每次HTTP請求中,使用request定義的bean都將產(chǎn)生一個新實例璃俗,只有在web應(yīng)用程序使用Spring時奴璃,該作用域才有效
|
|session
|同理
|
|global session
|同理
|
注意:
request和session作用域只在web應(yīng)用中才生效,并且必須在web應(yīng)用中增加額外的配置才會生效城豁,為了讓request苟穆,session兩個作用域生效,必須將HTTP請求對象綁定到為該請求提供服務(wù)的線程上,這使得具有request和session作用域的Bean實例能夠在后面的調(diào)用鏈中被訪問雳旅。
當(dāng)支持Servlet2.4及以上規(guī)范的web容器時跟磨,我們可以在web應(yīng)用的web.xml增加如下Listener配置,該Listener負責(zé)為request作用域生效:
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
如果僅使用了支持Servlet2.4以前規(guī)范的web容器攒盈,則該容器不支持Listener規(guī)范抵拘,故無法使用這種配置,可以使用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"/>
`這樣容器就會為每次HTTP請求生成一個lee.Person的實例當(dāng)該請求響應(yīng)結(jié)束時仑濒,該實例也隨之消失。`
`如果Web應(yīng)用直接使用Spring MVC作為MVC框架偷遗,即使用`SpringDispatchServlet`或`DispatchPortlet`來攔截所有用戶請求墩瞳,則`無需這些額外的配置`,`因為SpringDispatchServlet或DispatchPortlet已經(jīng)處理了所有和請求有關(guān)的狀態(tài)處理`氏豌。`
④**獲取容器的引用**:
>`通常情況下:`
Bean無需訪問Spring容器喉酌,而是通過Spring容器訪問的,即使 需要手動訪問Spring容器泵喘,程序也已通過類似下面的代碼獲取Spring容器 的引用泪电。
ApllicationContext cts = ClassPathApplalicationContext("bean.xml");
`但在一些極端的情況下`,可能Bean需要訪問Spring容器纪铺。Spring提供另一種方法訪問Spring容器:
>實現(xiàn)BeanFactoryAware接口的Bean相速,擁有訪問Spring容器的能力,實現(xiàn)BeanFactoryAware的Bean被容器實例化后鲜锚,會擁有一個引用指向創(chuàng)建他的BeanFactory突诬。BeanFactoryAware只有一個方法setBeanFactory(BeanFactory beanFactory)該參數(shù)指向創(chuàng)建他的BeanFactory。
>`缺點`:污染了代碼芜繁,使代碼與Spring接口耦合在一起旺隙,因此沒有特別的必要,建議不要直接訪問容器骏令。
---
4.**Bean實例的創(chuàng)建方式及對應(yīng)配置**:
>創(chuàng)建Bean的方法:
<li>調(diào)用構(gòu)造器創(chuàng)建Bean實例蔬捷;
<li>調(diào)用靜態(tài)工廠方法創(chuàng)建Bean;
<li>調(diào)用實例工廠創(chuàng)建Bean榔袋。
**調(diào)用靜態(tài)工廠方法創(chuàng)建Bean**:
>使用靜態(tài)工廠方法創(chuàng)建Bean實例時周拐,class屬性也必須指定,但此時class屬性并不是指定Bean實例的實現(xiàn)類凰兑,而是靜態(tài)工廠類速妖。因為Spring需要知道是用哪個工廠來創(chuàng)建Bean實例。另外聪黎,還需要使用factory-method來指定靜態(tài)工廠方法名,Spring將調(diào)用靜態(tài)工廠方法(可能包含一組參數(shù)),來返回一個Bean實例稿饰,一旦獲得了指定Bean實例锦秒,Spring后面的處理步驟與采用普通方法創(chuàng)建Bean實例則完全一樣。需要注意的是喉镰,當(dāng)使用靜態(tài)工廠方法來創(chuàng)建Bean時旅择,這個factory-method必須要是靜態(tài)的。這段闡述聽上去有點暈侣姆,話不多說生真,上代碼:
`先定義一個接口,靜態(tài)方法產(chǎn)生的將是該接口的實例:`
public interface Animal {
public void sayHello();
}
`下面是接口的兩個實現(xiàn)類:`
public class Cat implements Animal {
private String msg;
//依賴注入時必須的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;
//依賴注入時必須的setter方法
public void setMsg(String msg){
this.msg = msg;
}
@Override
public void sayHello(){
System.out.println(msg + "柱蟀,旺旺");
}
}
`下面的AnimalFactory工廠中包含了一個getAnimal的靜態(tài)方法,該方法將根據(jù)傳入的參數(shù)決定創(chuàng)建哪個對象蚜厉。這是`典型的靜態(tài)工廠設(shè)計模式`长已。`
public class AnimalFactory {
public static Animal getAnimal(String type){
if ("cat".equalsIgnoreCase(type)){
return new Cat();
} else {
return new Dog();
}
}
}
`如果需要指定Spring使用AnimalFactory來產(chǎn)生Animal對象,則可在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兩個Bean配置的class和factory-method完全相同昼牛,這是因為兩個實例都使用同一個靜態(tài)工廠類术瓮、同一個靜態(tài)工廠方法產(chǎn)生得到的。只是為這個靜態(tài)工廠方法指定的參數(shù)不同贰健,使用<constructor-arg />元素來為靜態(tài)工廠方法指定參數(shù)胞四。`
主程序獲取cat和dog兩個Bean實例的方法不變,同樣只需要調(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)工廠方法創(chuàng)建實例時必須提供工廠類和產(chǎn)生實例的靜態(tài)工廠方法。通過靜態(tài)工廠方法創(chuàng)建實例時需要對Spring配置文件做如下改變:
<li>`class屬性不在是Bean實例的實現(xiàn)類悬垃,而是生成Bean實例的靜態(tài)工廠類`
><li>`使用factory-method指定生產(chǎn)Bean實例的靜態(tài)工廠方法`
><li>`如果靜態(tài)工廠方法需要參數(shù)游昼,使用<constructor-arg />元素為其配置`
`當(dāng)我們指定Spring使用靜態(tài)工廠方法來創(chuàng)建Bean實例時,Spring將`先解析配置文件`尝蠕,并根據(jù)配置文件指定的信息烘豌,通過`反射調(diào)用靜態(tài)工廠類的靜態(tài)工廠方法`,并將該靜態(tài)工廠方法的返回值作為Bean實例看彼,在這個過程中廊佩,`Spring不再負責(zé)創(chuàng)建Bean實例`,Bean實例是由用戶提供的靜態(tài)工廠方法提供的靖榕。`
---
**調(diào)用實例工廠方法創(chuàng)建Bean**:
>實例工廠方法與靜態(tài)工廠方法只有一點不同:調(diào)用靜態(tài)工廠方法只需要使用工廠類即可标锄,調(diào)用實例工廠方法則必須使用工廠實例。所以在Spring配置上也只有一點區(qū)別:配置靜態(tài)工廠方法指定靜態(tài)工廠類茁计,配置實例工廠方法則指定工廠實例料皇。
`同樣是上面的例子將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>
測試類不用修改,輸出結(jié)果和上面相同。
---