2.3.1? XML配置的結構
一般配置文件結構如下:
?
java代碼:
-
<beans>??
-
????<
import
?resource=”resource1.xml”/>??
-
????<bean?id=”bean1”
class
=””></bean>??
-
????<bean?id=”bean2”
class
=””></bean>??
-
<bean?name=”bean2”
class
=””></bean>??
-
????<alias?alias=
"bean3"
?name=
"bean2"
/>??
-
????<
import
?resource=”resource2.xml”/>??
-
</beans>??
?
?
1、<bean>標簽主要用來進行Bean定義;
2、alias用于定義Bean別名的;
3、import用于導入其他配置文件的Bean定義,這是為了加載多個配置文件,當然也可以把這些配置文件構造為一個數組(new String[] {“config1.xml”, config2.xml})傳給ApplicationContext實現進行加載多個配置文件,那一個更適合由用戶決定;這兩種方式都是通過調用Bean Definition Reader 讀取Bean定義,內部實現沒有任何區別。<import>標簽可以放在<beans>下的任何位置,沒有順序關系。
?
2.3.2? Bean的配置
Spring IoC容器目的就是管理Bean,這些Bean將根據配置文件中的Bean定義進行創建,而Bean定義在容器內部由BeanDefinition對象表示,該定義主要包含以下信息:
●全限定類名(FQN):用于定義Bean的實現類;
●Bean行為定義:這些定義了Bean在容器中的行為;包括作用域(單例、原型創建)、是否惰性初始化及生命周期等;
●Bean創建方式定義:說明是通過構造器還是工廠方法創建Bean;
●Bean之間關系定義:即對其他bean的引用,也就是依賴關系定義,這些引用bean也可以稱之為同事bean 或依賴bean,也就是依賴注入。
Bean定義只有“全限定類名”在當使用構造器或靜態工廠方法進行實例化bean時是必須的,其他都是可選的定義。難道Spring只能通過配置方式來創建Bean嗎?回答當然不是,某些SingletonBeanRegistry接口實現類實現也允許將那些非BeanFactory創建的、已有的用戶對象注冊到容器中,這些對象必須是共享的,比如使用DefaultListableBeanFactory 的registerSingleton() 方法。不過建議采用元數據定義。
?
2.3.3?? ?Bean的命名
?????? 每個Bean可以有一個或多個id(或稱之為標識符或名字),在這里我們把
第一個id稱為“標識符”,其余id叫做“別名”
;這些id在IoC容器中必須唯一。如何為Bean指定id呢,有以下幾種方式;
?
?
一、? 不指定id,只配置必須的全限定類名,由IoC容器為其生成一個標識,客戶端必須通過接口“T getBean(Class<T> requiredType)”獲取Bean;
?
java代碼:
-
<bean?
class
=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>??????????????(
1
)??
?
測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test1()?{??
-
BeanFactory?beanFactory?=??
-
???
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean1.xml"
);??
-
????
??
-
????HelloApi?helloApi?=?beanFactory.getBean(HelloApi.
class
);??
-
????helloApi.sayHello();??
-
}??
?
?
?二、指定id,必須在Ioc容器中唯一;
?
java代碼:
-
<bean?id=”?bean”?
class
=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>????(
2
)??
?
測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test2()?{??
-
BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean2.xml"
);??
-
??
-
????HelloApi?bean?=?beanFactory.getBean(
"bean"
,?HelloApi.
class
);??
-
????bean.sayHello();??
-
}??
?
?
三、指定name,這樣name就是“標識符”,必須在Ioc容器中唯一;
?
java代碼:
-
<bean?name=”?bean”?
class
=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>?(
3
)??
?
測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test3()?{??
-
????BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean3.xml"
);??
-
????
??
-
HelloApi?bean?=?beanFactory.getBean(
"bean"
,?HelloApi.
class
);??
-
bean.sayHello();??
-
}??
?
?
四、指定id和name,id就是標識符,而name就是別名,必須在Ioc容器中唯一;
?
java代碼:
-
<bean?id=”bean1”name=”alias1”??
-
class
=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>??
-
<!--?如果id和name一樣,IoC容器能檢測到,并消除沖突?-->??
-
<bean?id=
"bean3"
?name=
"bean3"
?
class
=
"cn.javass.spring.chapter2.helloworld.HelloImpl"
/>??????????????(
4
)??
??
測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test4()?{??
-
BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean4.xml"
);??
-
????
??
-
????HelloApi?bean1?=?beanFactory.getBean(
"bean1"
,?HelloApi.
class
);??
-
????bean1.sayHello();??
-
????
??
-
????HelloApi?bean2?=?beanFactory.getBean(
"alias1"
,?HelloApi.
class
);??
-
????bean2.sayHello();??
-
????
??
-
????HelloApi?bean3?=?beanFactory.getBean(
"bean3"
,?HelloApi.
class
);??
-
????bean3.sayHello();??
-
????String[]?bean3Alias?=?beanFactory.getAliases(
"bean3"
);??
-
????
??
-
????Assert.assertEquals(
0
,?bean3Alias.length);??
-
}??
?
?
五、指定多個name,多個name用“,”、“;”、“ ”分割,第一個被用作標識符,其他的(alias1、alias2、alias3)是別名,所有標識符也必須在Ioc容器中唯一;
?
java代碼:
-
<bean?name=”?bean1;alias11,alias12;alias13?alias14”??
-
??????
class
=”?cn.javass.spring.chapter2.helloworld.HelloImpl”/>?????
-
<!--?當指定id時,name指定的標識符全部為別名?-->??
-
<bean?id=
"bean2"
?name=
"alias21;alias22"
??
-
class
=
"cn.javass.spring.chapter2.helloworld.HelloImpl"
/>??????????????(
5
)??
?
? 測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test5()?{??
-
BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean5.xml"
);??
-
????
??
-
????HelloApi?bean1?=?beanFactory.getBean(
"bean1"
,?HelloApi.
class
);??
-
????bean1.sayHello();??
-
????
??
-
????HelloApi?alias11?=?beanFactory.getBean(
"alias11"
,?HelloApi.
class
);??
-
????alias11.sayHello();??
-
????
??
-
????String[]?bean1Alias?=?beanFactory.getAliases(
"bean1"
);??
-
????System.out.println(
"=======namingbean5.xml?bean1?別名========"
);??
-
????
for
(String?alias?:?bean1Alias)?{??
-
????????System.out.println(alias);??
-
????}??
-
????Assert.assertEquals(
4
,?bean1Alias.length);??
-
????
??
-
????HelloApi?bean2?=?beanFactory.getBean(
"bean2"
,?HelloApi.
class
);??
-
????bean2.sayHello();??
-
????
??
-
????HelloApi?alias21?=?beanFactory.getBean(
"alias21"
,?HelloApi.
class
);??
-
????alias21.sayHello();??
-
????
??
-
????String[]?bean2Alias?=?beanFactory.getAliases(
"bean2"
);??
-
????System.out.println(
"=======namingbean5.xml?bean2?別名========"
);??
-
????
for
(String?alias?:?bean2Alias)?{??
-
????????System.out.println(alias);??
-
????}?????
-
????Assert.assertEquals(
2
,?bean2Alias.length);?????
-
}??
?
?
六、使用<alias>標簽指定別名,別名也必須在IoC容器中唯一
?
java代碼:
-
<bean?name=
"bean"
?
class
=
"cn.javass.spring.chapter2.helloworld.HelloImpl"
/>??
-
<alias?alias=
"alias1"
?name=
"bean"
/>??
-
<alias?alias=
"alias2"
?name=
"bean"
/>??????????????????????????????????(
6
)??
?
?測試代碼片段如下:
?
java代碼:
-
@Test
??
-
public
?
void
?test6()?{??
-
BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/namingbean6.xml"
);??
-
????
??
-
????HelloApi?bean?=?beanFactory.getBean(
"bean"
,?HelloApi.
class
);??
-
???bean.sayHello();??
-
????
??
-
????HelloApi?alias1?=?beanFactory.getBean(
"alias1"
,?HelloApi.
class
);??
-
????alias1.sayHello();??
-
????HelloApi?alias2?=?beanFactory.getBean(
"alias2"
,?HelloApi.
class
);??
-
????alias2.sayHello();??
-
????String[]?beanAlias?=?beanFactory.getAliases(
"bean"
);??
-
????System.out.println(
"=======namingbean6.xml?bean?別名========"
);??
-
????
for
(String?alias?:?beanAlias)?{??
-
????????System.out.println(alias);??
-
???}??
-
???System.out.println(
"=======namingbean6.xml?bean?別名========"
);??
-
????Assert.assertEquals(
2
,?beanAlias.length);??
-
?}??
?
以上測試代碼在cn.javass.spring.chapter2.NamingBeanTest.java文件中。
?
從定義來看,name或id如果指定它們中的一個時都作為“標識符”,那為什么還要有id和name同時存在呢?這是因為當使用基于XML的配置元數據時,在XML中id是一個真正的XML id屬性,因此當其他的定義來引用這個id時就體現出id的好處了,可以利用XML解析器來驗證引用的這個id是否存在,從而更早的發現是否引用了一個不存在的bean,而使用name,則可能要在真正使用bean時才能發現引用一個不存在的bean。
?
?
?●
Bean命名約定:
Bean的命名遵循XML命名規范,但最好符合Java命名規范,由“字母、數字、下劃線組成“,而且應該養成一個良好的命名習慣, 比如采用“駝峰式”,即第一個單詞首字母開始,從第二個單詞開始首字母大寫開始,這樣可以增加可讀性。
?
2.3.4? 實例化Bean
Spring IoC容器如何實例化Bean呢?傳統應用程序可以通過new和反射方式進行實例化Bean。而Spring IoC容器則需要根據Bean定義里的配置元數據使用反射機制來創建Bean。在Spring IoC容器中根據Bean定義創建Bean主要有以下幾種方式:
一、使用構造器實例化Bean:這是最簡單的方式,Spring IoC容器即能使用默認空構造器也能使用有參數構造器兩種方式創建Bean,如以下方式指定要創建的Bean類型:
?
使用空構造器進行定義,使用此種方式,class屬性指定的類必須有空構造器
?
java代碼:
-
<bean?name=
"bean1"
?
class
=
"cn.javass.spring.chapter2.HelloImpl2"
/>??
?
使用有參數構造器進行定義,使用此中方式,可以使用< constructor-arg >標簽指定構造器參數值,其中index表示位置,value表示常量值,也可以指定引用,指定引用使用ref來引用另一個Bean定義,后邊會詳細介紹:
?
java代碼:
-
<bean?name=
"bean2"
?
class
=
"cn.javass.spring.chapter2.HelloImpl2"
>??
-
<!--?指定構造器參數?-->??
-
?????<constructor-arg?index=
"0"
?value=
"Hello?Spring!"
/>??
-
</bean>??
?
知道如何配置了,讓我們做個例子的例子來實踐一下吧:
(1)準備Bean class(HelloImpl2.java),該類有一個空構造器和一個有參構造器:
?
java代碼:
-
package
?cn.javass.spring.chapter2;???
-
??
public
?
class
?HelloImpl2?
implements
?HelloApi?{??
-
???????????
private
?String?message;??
-
??????
public
?HelloImpl2()?{??
-
??????????????????
this
.message?=?
"Hello?World!"
;??
-
???????????}??
-
?????????Public?HelloImpl2(String?message)?{??
-
??????????????????
this
.message?=?message;??
-
???????????}??
-
???????????
@Override
??
-
???????????
public
?
void
?sayHello()?{??
-
??????????????????System.out.println(message);??
-
???????????}??
-
}??
-
???
?
(2)在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義,如下所示:
?
java代碼:
-
<!--使用默認構造參數-->??
-
<bean?name=
"bean1"
?
class
=
"cn.javass.spring.chapter2.HelloImpl2"
/>??
-
????<!--使用有參數構造參數-->??
-
???
-
<bean?name=
"bean2"
?
class
=
"cn.javass.spring.chapter2.HelloImpl2"
>??
-
<!--?指定構造器參數?-->??
-
????<constructor-arg?index=
"0"
?value=
"Hello?Spring!"
/>??
-
</bean>??
?
?
(3)配置完了,讓我們寫段測試代碼(InstantiatingContainerTest)來看下是否工作吧:
?
java代碼:
-
@Test
??
-
public
?
void
?testInstantiatingBeanByConstructor()?{??
-
???????
??
-
?????BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/instantiatingBean.xml"
);??
-
???????HelloApi?bean1?=?beanFactory.getBean(
"bean1"
,?HelloApi.
class
);??
-
???????bean1.sayHello();??
-
???????HelloApi?bean2?=?beanFactory.getBean(
"bean2"
,?HelloApi.
class
);??
-
???????bean2.sayHello();??
-
}??
?
?
二、使用靜態工廠方式實例化Bean,使用這種方式除了指定必須的class屬性,還要指定factory-method屬性來指定實例化Bean的方法,而且使用靜態工廠方法也允許指定方法參數,spring IoC容器將調用此屬性指定的方法來獲取Bean,配置如下所示:
?? (1)先來看看靜態工廠類代碼吧HelloApiStaticFactory:
?
java代碼:
-
public
?
class
?HelloApiStaticFactory?{??
-
????
??
-
???????
public
?
static
?HelloApi?newInstance(String?message)?{??
-
??????????????
??
-
???????????
return
?
new
?HelloImpl2(message);??
-
}??
-
}??
?
?
(2)靜態工廠寫完了,讓我們在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
?
java代碼:
-
<!--?使用靜態工廠方法?-->??
-
<bean?id=
"bean3"
?
class
=
"cn.javass.spring.chapter2.HelloApiStaticFactory"
?factory-method=
"newInstance"
>??
-
?????<constructor-arg?index=
"0"
?value=
"Hello?Spring!"
/>??
-
</bean>??
?
?
(3)配置完了,寫段測試代碼來測試一下吧,InstantiatingBeanTest:
?
java代碼:
-
@Test
??
-
public
?
void
?testInstantiatingBeanByStaticFactory()?{??
-
???????
??
-
???????BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chaper2/instantiatingBean.xml"
);??
-
???????HelloApi?bean3?=?beanFactory.getBean(
"bean3"
,?HelloApi.
class
);??
-
???????bean3.sayHello();??
-
}??
?
?
三、使用實例工廠方法實例化Bean,使用這種方式不能指定class屬性,此時必須使用factory-bean屬性來指定工廠Bean,factory-method屬性指定實例化Bean的方法,而且使用實例工廠方法允許指定方法參數,方式和使用構造器方式一樣,配置如下:
(1)實例工廠類代碼(HelloApiInstanceFactory.java)如下:
?
java代碼:
-
??????
-
package
?cn.javass.spring.chapter2;??
-
public
?
class
?HelloApiInstanceFactory?{??
-
public
?HelloApi?newInstance(String?message)?{??
-
??????????
return
?
new
?HelloImpl2(message);??
-
???}??
-
}??
-
???
-
???
?
(2)讓我們在配置文件(resources/chapter2/instantiatingBean.xml)配置Bean定義:
?
java代碼:
-
<!—
1
、定義實例工廠Bean?-->??
-
<bean?id=
"beanInstanceFactory"
??
-
class
=
"cn.javass.spring.chapter2.HelloApiInstanceFactory"
/>??
-
<!—
2
、使用實例工廠Bean創建Bean?-->??
-
<bean?id=
"bean4"
??
-
factory-bean=
"beanInstanceFactory"
??
-
?????factory-method=
"newInstance"
>??
-
?<constructor-arg?index=
"0"
?value=
"Hello?Spring!"
></constructor-arg>??
-
</bean>??
?
(3)測試代碼InstantiatingBeanTest:
?
java代碼:
-
@Test
??
-
public
?
void
?testInstantiatingBeanByInstanceFactory()?{??
-
??
-
???????BeanFactory?beanFactory?=??
-
new
?ClassPathXmlApplicationContext(
"chapter2/instantiatingBean.xml"
);??
-
???????HelloApi?bean4?=?beanFactory.getBean(
"bean4"
,?HelloApi.
class
);??
-
???????bean4.sayHello();??
-
}??
?
?????? 通過以上例子我們已經基本掌握了如何實例化Bean了,大家是否注意到?這三種方式只是配置不一樣,從獲取方式看完全一樣,沒有任何不同。這也是Spring IoC的魅力,Spring IoC幫你創建Bean,我們只管使用就可以了,是不是很簡單。
?
2.3.5? 小結
?????? 到此我們已經講完了Spring IoC基礎部分,包括IoC容器概念,如何實例化容器,Bean配置、命名及實例化,Bean獲取等等。不知大家是否注意到到目前為止,我們只能通過簡單的實例化Bean,沒有涉及Bean之間關系。接下來一章讓我們進入配置Bean之間關系章節,也就是依賴注入。?
?
同步發布到私塾在線【
http://***/forum/blogPost/list/2433.html
】
【第二章】 IoC 之 2.3 IoC的配置使用——跟我學Spring3