使用Spring的IoC容器
3.1 BeanFactory和ApplicationContext的介紹
3.1.1
BeanFactory介紹 BeanFactory是一個類工廠,但它和傳統的類工廠不一樣,傳統的類工廠僅生成一個類的對象,或幾個實現某一相同接口類的對象。而BeanFactory是通用的工廠,他能夠建立和管理各類類的對象。這些可被建立和管理的對象自己沒有什麼特別之處,僅是一個簡單的POJO,Spring稱這些被建立和被管理的Java對象爲Bean。咱們知道JavaBean是要知足必定規範的,如必須提供一個默認不帶參的構造函數、不依賴於某一特定的容器等,但Spring中所說的Bean比JavaBean更寬泛一些,因此不須要額外服務支持的POJO均可以是Bean。
Spring爲BeanFactory提供了多種實現,最經常使用的是XmlBeanFactory。咱們該如何得到一個XmlBeanFactory呢?
代碼清單1
Resource resource = new FileSystemResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
或
ClassPathResource resource = new ClassPathResource("beans.xml");
BeanFactory factory = new XmlBeanFactory(resource);
代碼清單1中咱們經過FileSystemResource和ClassPathResource都得到了XmlBeanFactory。可是咱們有了XmlBeanFactory對象又能幹什麼用呢?
代碼清單2
public
class
Foo {
private
String
name
;
public
void
setName(String name) {
this
.
name
= name;
}
public
String toStirng(){
return
"Foo Name is :"
+
this
.
name
;
}
}
<?
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:p
=
"http://www.springframework.org/schema/p"
xmlns:context
=
"http://www.springframework.org/schema/context"
xsi:schemaLocation
=
"
[url]http://www.springframework.org/schema/beans[/url] [url]http://www.springframework.org/schema/beans/spring-beans-2.5.xsd[/url]
[url]http://www.springframework.org/schema/context[/url] [url]http://www.springframework.org/schema/context/spring-context-2.5.xsd[/url]"
>
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo"
/>
</
bean
>
</
beans
>
import
org.springframework.beans.factory.BeanFactory;
import
org.springframework.beans.factory.xml.XmlBeanFactory;
import
org.springframework.core.io.ClassPathResource;
public
class
Test {
public
static
void
main(String[] args) {
//
定義
Spring
配置文件
ClassPathResource resource =
new
ClassPathResource(
"spring-config-beans.xml"
);
//
實例化
BeanFactory
BeanFactory factory =
new
XmlBeanFactory(resource);
//
根據配置文件中的
id
得到
Bean
Foo foo = (Foo) factory.getBean(
"foo"
);
System.
out
.println(foo.toStirng());
}
}
運行結果
Foo Name is :Foo
代碼清單
2
中咱們首先定義了一個很普通的
java
類
Foo.java
而後在
Spring
配置文件中將其配置
,
關鍵的是咱們的
Test.java
類咱們首先實例化了
ClassPathResource
對象,在實例化時咱們已經告訴了它
Spring
配置文件的名稱,實例化
BeanFactory
後咱們經過
factory.getBean
就能夠得到由
Spring
管理的
Bean
了。咱們驚奇的發現
Spring
居然幫咱們把
Foo
對象中
name
屬性的數據裝配進去了。
3.1.2
A
pplicationContext
介紹
若是說
BeanFactory
是
Spring
的心臟,那麼
ApplicationContext
就是
Spring
的五臟六腑和軀幹四肢了。
ApplicationContext
接口由
BeanFactory
派生而來,提供了更多面向實際應用的功能,在
BeanFactory
中,不少功能須要以編程的方式進行操做,而在
ApplicationContext
中則能夠經過配置的方式進行控制。
簡而言之,BeanFactory
提供了配製框架及基本功能,而ApplicationContext
則增長了更多支持企業核心內容的功能。ApplicationContext
徹底由BeanFactory
擴展而來,於是BeanFactory
所具有的能力和行爲也適用於ApplicationContext
。
3.2 Bean的基本配置
每一個bean都有一個或多個id(或稱之爲標識符或名稱,在術語上能夠理 解成 一回事)。這些id在當前IoC容器中必須惟一。若是一個bean有多 個id, 那麼其餘的id在本質上將被認爲是別名。
當使用基於XML的配置元數據時,將經過id
或name
屬性來指定bean標識 符。 id
屬性具備惟一性,並且是一個真正的XML ID屬性,所以其餘xml 元素在引用該id時,能夠利用XML解析器的驗證功能。一般狀況下最好爲 bean指定一個id。儘管XML規範規定了XML ID命名的有效字符,可是bean 標識符的定義不受該限制,由於除了使用指定的XML字符來做爲id,還能夠 爲bean指定別名,要實現這一點能夠在name
屬性中使用逗號、冒號或者空 格將多個id分隔。
值得注意的是,爲一個bean提供一個name並非必須的,若是沒有指定, 那麼容器將爲其生成一個唯一的name。
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"/
>
通常狀況下,
SpringIoC
容器中的一個
Bean
即對應配置文件中的一個
<bean>
,這種鏡像性的對應關係很容易理解。其中
id
爲這個
Bean
的名稱,經過容器的
getBean(「foo」)
便可獲取對應的
Bean
,在容器中起到定位查找的做用,是外部程序和
SpringIoC
容器進行通訊的橋樑。
Class
屬性指定了
Bean
對應的實現類。
3.3 依賴注入
Spring支持兩種依賴注入方式,分別是屬性注入和構造函數注入。。
3.3.1
屬性注入
屬性注入即經過setXxx()方法注入Bean的屬性值或依賴對象,因爲屬性注入方式具備可選擇性和靈活性高的優勢,所以屬性注入是實際應用中最經常使用的注入方式。
代碼清單1
public
class
Foo {
private
String
name
;
public
void
setName(String name) {
this
.
name
= name;
}
public
String toStirng(){
return
"Foo Name is :"
+
this
.
name
;
}
}
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
property
name
=
"name"
value
=
"Foo"
/>
</
bean
>
Foo類中定義了一個屬性name,並提供了對應的Setter方法,咱們配置了一個Bean,併爲該Bean的name屬性提供了屬性值。具體來講,Bean的每個屬性對應一個
<property>
標籤,
name
爲屬性的名稱,在
Bean
實現類中擁有與其的對應的
Setter
方法
name
對應
setName()
方法。
3.3.2
構造函數注入
構造函數注入是除屬性注入以外的另外一種經常使用注入方式,它保證一些必要的屬性在
Bean
實例化時就獲得設置,它保證了
Bean
實例在實例化後就可使用。
代碼清單
1
public
class
Foo {
private
String
name
;
private
int
age
;
public
Foo(String name,
int
age){
this
.
name
= name;
this
.
age
= age;
}
public
String toStirng(){
return
"Foo Name is :"
+
this
.
name
;
}
}
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
constructor-arg
type
=
"int"
>
<
value
>
20
</
value
>
</
constructor-arg
>
<
constructor-arg
type
=
"java.lang.String"
>
<
value
>
Foo
</
value
>
</
constructor-arg
>
</
bean
>
代碼清單
1
中咱們定義了一個構造函數,接受一個
String
類型的入參,配置文件中咱們配別經過
<constructor-arg>
元素中定義了
type
類型爲
java.lang.String
和
int
的兩個元素,
Spring
會經過
type
類型來對構造函數進行注入,所以咱們在配置文件和構造函數入參順序不一樣的狀況下仍是能夠成功注入。可是咱們對於多個構造函數而且類型都同樣的時候咱們改怎麼辦呢?
代碼清單
2
<
bean
id
=
"foo"
class
=
"com.tony.test.Foo"
>
<
constructor-arg
index
=
"0"
value
=
"Foo"
/>
<
constructor-arg
index
=
"1"
value
=
"20"
/>
</
bean
>
只要修改配置文件中
<constructor-arg>
元素把
type
屬性改成
index
而且指定參數的索引就可一了,這裏必定要注意索引是從
0
開始的。
3.4 Bean
的做用域
在配置文件中定義
Bean
時,用戶不單能夠配置
Bean
的屬性值以及相互之間的依賴關係,還能夠定義
Bean
的做用域。做用域將對
Bean
的生命週期和建立方式產生影響。在低版本的
Spring
中,僅有兩個做用域:
singleton
和
prototype
,在
Spring2.0
中,針對
WebApplicationContext
新增長了
3
個做用域。
singleton
<bean id="foo" class="…" scope="singleton"/>
在
SpringIoC
容器中僅存在一個
Bean
實例,
Bean
以單實例的方式存在。
prototype
<bean id="foo" class="…" scope="prototype"/>
每次從容器中調用
Bean
時,都返回一個新的實例,即每次調用
getBean
時,至關於執行
newXxxBean
的操做。
request
<
bean
id
=
"foo"
class
=
"…"
scope
=
"
request
"
/>
每次HTTP請求都會建立一個新的Bean。該做用域僅適用於WebApplicationContext環境。
session
<
bean
id
=
"foo"
class
=
"…"
scope
=
"
session
"
/>
同一個HTTPSession共享一個Bean,不一樣HTTPSession使用不一樣的Bean。該做用域僅適用於WebApplicationContext環境。
globalSession
<
bean
id
=
"foo"
class
=
"…"
scope
=
"
globalSession
"
/>
同一個全局Session共享一個Bean,通常用於Protlet應用環境。該做用域僅適用於WebApplicationContext環境。