3.1.1? 依賴和依賴注入
?????? 傳統(tǒng)應(yīng)用程序設(shè)計(jì)中所說(shuō)的依賴一般指“類之間的關(guān)系”,那先讓我們復(fù)習(xí)一下類之間的關(guān)系:
? ? ? 泛化: 表示類與類之間的繼承關(guān)系、接口與接口之間的繼承關(guān)系;
? ? ? 實(shí)現(xiàn): 表示類對(duì)接口的實(shí)現(xiàn);
? ? ? 依賴: 當(dāng)類與類之間有使用關(guān)系時(shí)就屬于依賴關(guān)系,不同于關(guān)聯(lián)關(guān)系,依賴不具有“擁有關(guān)系”,而是一種“相識(shí)關(guān)系”,只在某個(gè)特定地方(比如某個(gè)方法體內(nèi))才有關(guān)系。
? ? ? 關(guān)聯(lián): 表示類與類或類與接口之間的依賴關(guān)系,表現(xiàn)為“擁有關(guān)系”;具體到代碼可以用實(shí)例變量來(lái)表示;
? ? ? 聚合: 屬于是關(guān)聯(lián)的特殊情況,體現(xiàn)部分-整體關(guān)系,是一種弱擁有關(guān)系;整體和部分可以有不一樣的生命周期;是一種弱關(guān)聯(lián);
? ? ? 組合: 屬于是關(guān)聯(lián)的特殊情況,也體現(xiàn)了體現(xiàn)部分-整體關(guān)系,是一種強(qiáng)“擁有關(guān)系”;整體與部分有相同的生命周期,是一種強(qiáng)關(guān)聯(lián);
Spring IoC容器的依賴有兩層含義: Bean依賴容器 和 容器注入Bean的依賴資源 :
? ? ? Bean依賴容器: 也就是說(shuō)Bean要依賴于容器,這里的依賴是指容器負(fù)責(zé)創(chuàng)建Bean并管理Bean的生命周期,正是由于由容器來(lái)控制創(chuàng)建Bean并注入依賴,也就是控制權(quán)被反轉(zhuǎn)了,這也正是IoC名字的由來(lái), 此處的有依賴是指Bean和容器之間的依賴關(guān)系 。
? ? ? 容器注入Bean的依賴資源: 容器負(fù)責(zé)注入Bean的依賴資源,依賴資源可以是Bean、外部文件、常量數(shù)據(jù)等,在Java中都反映為對(duì)象,并且由容器負(fù)責(zé)組裝Bean之間的依賴關(guān)系, 此處的依賴是指Bean之間的依賴關(guān)系 , 可以認(rèn)為是傳統(tǒng)類與類之間的“關(guān)聯(lián)”、“聚合”、“組合”關(guān)系 。
?
為什么要應(yīng)用依賴注入,應(yīng)用依賴注入能給我們帶來(lái)哪些好處呢?
? ? ? 動(dòng)態(tài)替換Bean依賴對(duì)象,程序更靈活: 替換Bean依賴對(duì)象,無(wú)需修改源文件:應(yīng)用依賴注入后,由于可以采用配置文件方式實(shí)現(xiàn),從而能隨時(shí)動(dòng)態(tài)的替換Bean的依賴對(duì)象,無(wú)需修改java源文件;
? ? ? 更好實(shí)踐面向接口編程,代碼更清晰: 在Bean中只需指定依賴對(duì)象的接口,接口定義依賴對(duì)象完成的功能,通過(guò)容器注入依賴實(shí)現(xiàn);
? ? ? 更好實(shí)踐優(yōu)先使用對(duì)象組合,而不是類繼承: 因?yàn)镮oC容器采用注入依賴,也就是組合對(duì)象,從而更好的實(shí)踐對(duì)象組合。
- 采用對(duì)象組合,Bean的功能可能由幾個(gè)依賴Bean的功能組合而成,其Bean本身可能只提供少許功能或根本無(wú)任何功能,全部委托給依賴Bean,對(duì)象組合具有動(dòng)態(tài)性,能更方便的替換掉依賴Bean,從而改變Bean功能;
- 而如果采用類繼承,Bean沒(méi)有依賴Bean,而是采用繼承方式添加新功能,,而且功能是在編譯時(shí)就確定了,不具有動(dòng)態(tài)性,而且采用類繼承導(dǎo)致Bean與子Bean之間高度耦合,難以復(fù)用。
? ? ? 增加Bean可復(fù)用性: 依賴于對(duì)象組合,Bean更可復(fù)用且復(fù)用更簡(jiǎn)單;
? ? ? 降低Bean之間耦合: 由于我們完全采用面向接口編程,在代碼中沒(méi)有直接引用Bean依賴實(shí)現(xiàn),全部引用接口,而且不會(huì)出現(xiàn)顯示的創(chuàng)建依賴對(duì)象代碼,而且這些依賴是由容器來(lái)注入,很容易替換依賴實(shí)現(xiàn)類,從而降低Bean與依賴之間耦合;
? ? ? 代碼結(jié)構(gòu)更清晰: 要應(yīng)用依賴注入,代碼結(jié)構(gòu)要按照規(guī)約方式進(jìn)行書寫,從而更好的應(yīng)用一些最佳實(shí)踐,因此代碼結(jié)構(gòu)更清晰。
?
從以上我們可以看出,其實(shí)依賴注入只是一種裝配對(duì)象的手段,設(shè)計(jì)的類結(jié)構(gòu)才是基礎(chǔ),如果設(shè)計(jì)的類結(jié)構(gòu)不支持依賴注入,Spring IoC容器也注入不了任何東西,從而從根本上說(shuō) “如何設(shè)計(jì)好類結(jié)構(gòu)才是關(guān)鍵,依賴注入只是一種裝配對(duì)象手段”。
前邊IoC一章我們已經(jīng)了解了Bean依賴容器,那容器如何注入Bean的依賴資源,Spring IoC容器注入依賴資源主要有以下兩種基本實(shí)現(xiàn)方式:
? ? ? 構(gòu)造器注入: 就是容器實(shí)例化Bean時(shí)注入那些依賴,通過(guò)在在Bean定義中指定構(gòu)造器參數(shù)進(jìn)行注入依賴,包括實(shí)例工廠方法參數(shù)注入依賴,但靜態(tài)工廠方法參數(shù)不允許注入依賴;
? ? ? setter注入 :通過(guò)setter方法進(jìn)行注入依賴;
? ? ? 方法注入 :能通過(guò)配置方式替換掉Bean方法,也就是通過(guò)配置改變Bean方法 功能。
?
我們已經(jīng)知道注入實(shí)現(xiàn)方式了,接下來(lái)讓我們來(lái)看看具體配置吧。
?
?
3.1.2? 構(gòu)造器注入
?????? 使用構(gòu)造器注入通過(guò)配置構(gòu)造器參數(shù)實(shí)現(xiàn),構(gòu)造器參數(shù)就是依賴。除了構(gòu)造器方式,還有靜態(tài)工廠、實(shí)例工廠方法可以進(jìn)行構(gòu)造器注入。如圖3-1所示:
?
圖3-1 實(shí)例化
構(gòu)造器注入可以根據(jù)參數(shù)索引注入、參數(shù)類型注入或Spring3支持的參數(shù)名注入,但參數(shù)名注入是有限制的,需要使用在編譯程序時(shí)打開(kāi)調(diào)試模式(即在編譯時(shí)使用“javac –g:vars”在class文件中生成變量調(diào)試信息,默認(rèn)是不包含變量調(diào)試信息的,從而能獲取參數(shù)名字,否則獲取不到參數(shù)名字)或在構(gòu)造器上使用@ConstructorProperties(java.beans.ConstructorProperties)注解來(lái)指定參數(shù)名。
首先讓我們準(zhǔn)備測(cè)試構(gòu)造器類HelloImpl3.java,該類只有一個(gè)包含兩個(gè)參數(shù)的構(gòu)造器:
?
- package ?cn.javass.spring.chapter3.helloworld;??
- public ? class ?HelloImpl3? implements ?HelloApi?{??
- ???? private ?String?message;??
- private ? int ?index;??
- //@java.beans.ConstructorProperties({"message",?"index"}) ??
- ???? public ?HelloImpl3(String?message,? int ?index)?{??
- ???????? this .message?=?message;??
- ???????? this .index?=?index;??
- ????}??
- ???? @Override ??
- ???? public ? void ?sayHello()?{??
- ????????System.out.println(index?+? ":" ?+?message);??
- ????}??
- }??
?
一、根據(jù)參數(shù)索引注入,使用標(biāo)簽“<constructor-arg index="1" value="1"/>”來(lái)指定注入的依賴,其中“index”表示索引,從0開(kāi)始,即第一個(gè)參數(shù)索引為0,“value”來(lái)指定注入的常量值,配置方式如下:
??????
二、根據(jù)參數(shù)類型進(jìn)行注入,使用標(biāo)簽“<constructor-arg type="java.lang.String" value="Hello World!"/>”來(lái)指定注入的依賴,其中“type”表示需要匹配的參數(shù)類型,可以是基本類型也可以是其他類型,如“int”、“java.lang.String”,“value”來(lái)指定注入的常量值,配置方式如下:
?
三、根據(jù)參數(shù)名進(jìn)行注入,使用標(biāo)簽“<constructor-arg name="message" value="Hello World!"/>”來(lái)指定注入的依賴,其中“name”表示需要匹配的參數(shù)名字,“value”來(lái)指定注入的常量值,配置方式如下:
??
四、讓我們來(lái)用具體的例子來(lái)看一下構(gòu)造器注入怎么使用吧。
(1)首先準(zhǔn)備Bean類,在此我們就使用“HelloImpl3”這個(gè)類。
(2)有了Bean類,接下來(lái)要進(jìn)行Bean定義配置,我們需要配置三個(gè)Bean來(lái)完成上述三種依賴注入測(cè)試,其中Bean ”byIndex”是通過(guò)索引注入依賴;Bean ”byType”是根據(jù)類型進(jìn)行注入依賴;Bean ”byName”是根據(jù)參數(shù)名字進(jìn)行注入依賴,具體配置文件(resources/chapter3/ constructorDependencyInject.xml)如下:
?
- <!--?通過(guò)構(gòu)造器參數(shù)索引方式依賴注入?-->??
- <bean?id= "byIndex" ? class = "cn.javass.spring.chapter3.HelloImpl3" >??
- <constructor-arg?index= "0" ?value= "Hello?World!" />??
- ????<constructor-arg?index= "1" ?value= "1" />??
- </bean>??
- <!--?通過(guò)構(gòu)造器參數(shù)類型方式依賴注入?-->??
- <bean?id= "byType" ? class = "cn.javass.spring.chapter3.HelloImpl3" >??
- ???<constructor-arg?type= "java.lang.String" ?value= "Hello?World!" />??
- ???<constructor-arg?type= "int" ?value= "2" />??
- </bean>??
- <!--?通過(guò)構(gòu)造器參數(shù)名稱方式依賴注入?-->??
- <bean?id= "byName" ? class = "cn.javass.spring.chapter3.HelloImpl3" >??
- ???<constructor-arg?name= "message" ?value= "Hello?World!" />??
- ???<constructor-arg?name= "index" ?value= "3" />??
- </bean>??
- ???
- ???
?
(3)配置完畢后,在測(cè)試之前,因?yàn)槲覀兪褂昧送ㄟ^(guò)構(gòu)造器參數(shù)名字注入方式,請(qǐng)確保編譯時(shí)class文件包含“變量信息”,具體查看編譯時(shí)是否包含“變量調(diào)試信息”請(qǐng)右擊項(xiàng)目,在彈出的對(duì)話框選擇屬性;然后在彈出的對(duì)話框選擇“Java Compiler”條目,在“Class 文件 生成”框中選擇“添加變量信息到Class文件(調(diào)試器使用)”,具體如圖3-2:
?
圖3-2 編譯時(shí)打開(kāi)“添加變量信息選項(xiàng)”
(4)接下來(lái)讓我們測(cè)試一下配置是否工作,具體測(cè)試代碼(cn.javass.spring.chapter3. DependencyInjectTest)如下:
?
- @Test ??
- public ? void ?testConstructorDependencyInjectTest()?{????????
- BeanFactory?beanFactory?=?? new ?ClassPathXmlApplicationContext( "chapter3/constructorDependencyInject.xml" );??
- //獲取根據(jù)參數(shù)索引依賴注入的Bean ??
- HelloApi?byIndex?=?beanFactory.getBean( "byIndex" ,?HelloApi. class );??
- byIndex.sayHello();??
- //獲取根據(jù)參數(shù)類型依賴注入的Bean ??
- HelloApi?byType?=?beanFactory.getBean( "byType" ,?HelloApi. class );??
- byType.sayHello();??
- //獲取根據(jù)參數(shù)名字依賴注入的Bean ??
- HelloApi?byName?=?beanFactory.getBean( "byName" ,?HelloApi. class );??
- byName.sayHello();??
- }??
?
?????? 通過(guò)以上測(cè)試我們已經(jīng)會(huì)基本的構(gòu)造器注入配置了,在測(cè)試通過(guò)參數(shù)名字注入時(shí),除了可以使用以上方式,還可以通過(guò)在構(gòu)造器上添加@java.beans.ConstructorProperties({"message", "index"})注解來(lái)指定參數(shù)名字,在HelloImpl3構(gòu)造器上把注釋掉的“ConstructorProperties”打開(kāi)就可以了,這個(gè)就留給大家做練習(xí),自己配置然后測(cè)試一下。
?
五、大家已經(jīng)會(huì)了構(gòu)造器注入,那讓我們?cè)倏匆幌蚂o態(tài)工廠方法注入和實(shí)例工廠注入吧,其實(shí)它們注入配置是完全一樣,在此我們只示范一下靜態(tài)工廠注入方式和實(shí)例工廠方式配置,測(cè)試就留給大家自己練習(xí):
?????? (1)靜態(tài)工廠類
? ? ??
- //靜態(tài)工廠類 ??
- package ?cn.javass.spring.chapter3;??
- import ?cn.javass.spring.chapter2.helloworld.HelloApi;??
- public ? class ?DependencyInjectByStaticFactory?{??
- ??????? public ? static ?HelloApi?newInstance(String?message,? int ?index)?{??
- ?????????????? return ? new ?HelloImpl3(message,?index);??
- ???????}??
- }??
?
?????? ?靜態(tài)工廠類Bean定義配置文件(chapter3/staticFactoryDependencyInject.xml)
?
?
- <bean?id= "byIndex" ??
- class = "cn.javass.spring.chapter3.DependencyInjectByStaticFactory" ?factory-method= "newInstance" >??
- <constructor-arg?index= "0" ?value= "Hello?World!" />??
- <constructor-arg?index= "1" ?value= "1" />??
- </bean>??
- <bean?id= "byType" ??
- class = "cn.javass.spring.chapter3.DependencyInjectByStaticFactory" ?factory-method= "newInstance" >??
- <constructor-arg?type= "java.lang.String" ?value= "Hello?World!" />??
- ???????<constructor-arg?type= "int" ?value= "2" />??
- </bean>??
- <bean?id= "byName" ??
- class = "cn.javass.spring.chapter3.DependencyInjectByStaticFactory" ?factory-method= "newInstance" >??
- ???????<constructor-arg?name= "message" ?value= "Hello?World!" />??
- ???????<constructor-arg?name= "index" ?value= "3" />??
- </bean>??
?
?
(2)實(shí)例工廠類
?
- //實(shí)例工廠類 ??
- package ?cn.javass.spring.chapter3;??
- import ?cn.javass.spring.chapter2.helloworld.HelloApi;??
- public ? class ?DependencyInjectByInstanceFactory?{??
- ???? public ?HelloApi?newInstance(String?message,? int ?index)?{??
- ???????? return ? new ?HelloImpl3(message,?index);??
- ????}??
- }??
?
? ? ? ? 實(shí)例工廠類Bean定義配置文件(chapter3/instanceFactoryDependencyInject.xml)
?
?
- <bean?id= "instanceFactory" ??
- class = "cn.javass.spring.chapter3.DependencyInjectByInstanceFactory" />??
- ???
- <bean?id= "byIndex" ??
- factory-bean= "instanceFactory" ??factory-method= "newInstance" >??
- ????<constructor-arg?index= "0" ?value= "Hello?World!" />??
- ???????<constructor-arg?index= "1" ?value= "1" />??
- </bean>??
- <bean?id= "byType" ??
- factory-bean= "instanceFactory" ?factory-method= "newInstance" >??
- <constructor-arg?type= "java.lang.String" ?value= "Hello?World!" />??
- <constructor-arg?type= "int" ?value= "2" />??
- </bean>??
- <bean?id= "byName" ??
- factory-bean= "instanceFactory" ?factory-method= "newInstance" >??
- <constructor-arg?name= "message" ?value= "Hello?World!" />??
- <constructor-arg?name= "index" ?value= "3" />??
- </bean>??
?
?????? (3)測(cè)試代碼和構(gòu)造器方式完全一樣,只是配置文件不一樣,大家只需把測(cè)試文件改一下就可以了。還有一點(diǎn)需要大家注意就是靜態(tài)工廠方式和實(shí)例工廠方式根據(jù)參數(shù)名字注入的方式只支持通過(guò)在class文件中添加“變量調(diào)試信息”方式才能運(yùn)行,ConstructorProperties注解方式不能工作,它只對(duì)構(gòu)造器方式起作用, 不建議使用根據(jù)參數(shù)名進(jìn)行構(gòu)造器注入 。
?
?
3.1.3? setter注入
?????? setter注入,是通過(guò)在通過(guò)構(gòu)造器、靜態(tài)工廠或?qū)嵗S實(shí)例好Bean后,通過(guò)調(diào)用Bean類的setter方法進(jìn)行注入依賴,如圖3-3所示:
?
圖3-3 setter注入方式
?????? setter注入方式只有一種根據(jù)setter名字進(jìn)行注入:
?
?????? 知道配置方式了,接下來(lái)先讓我們來(lái)做個(gè)簡(jiǎn)單例子吧。
?
(1)準(zhǔn)備測(cè)試類HelloImpl4,需要兩個(gè)setter方法“setMessage”和“setIndex”:
?
- package ?cn.javass.spring.chapter3;??
- import ?cn.javass.spring.chapter2.helloworld.HelloApi;??
- public ? class ?HelloImpl4? implements ?HelloApi?{??
- ???? private ?String?message;??
- ???? private ? int ?index;??
- //setter方法 ??
- ???? public ? void ?setMessage(String?message)?{??
- ???????? this .message?=?message;??
- ????}??
- ???? public ? void ?setIndex( int ?index)?{??
- ???????? this .index?=?index;??
- ????}??
- ???? @Override ??
- ???? public ? void ?sayHello()?{??
- ????????System.out.println(index?+? ":" ?+?message);??
- ????}??
- }??
?
?????? (2)配置Bean定義,具體配置文件(resources/chapter3/setterDependencyInject.xml)片段如下:
?
- <!--?通過(guò)setter方式進(jìn)行依賴注入?-->??
- ????<bean?id= "bean" ? class = "cn.javass.spring.chapter3.HelloImpl4" >??
- ????????<property?name= "message" ?value= "Hello?World!" />??
- ????????<property?name= "index" >??
- ????????????<value> 1 </value>??
- ????????</property>??
- ????</bean>??
?
? ? ??
(3)該寫測(cè)試進(jìn)行測(cè)試一下是否滿足能工作了,其實(shí)測(cè)試代碼一點(diǎn)沒(méi)變,變的是配置:
?
- @Test ??
- public ? void ?testSetterDependencyInject()?{??
- ????BeanFactory?beanFactory?=??
- new ?ClassPathXmlApplicationContext( "chapter3/setterDependencyInject.xml" );??
- ???HelloApi?bean?=?beanFactory.getBean( "bean" ,?HelloApi. class );??
- ????bean.sayHello();??
- }??
??
?????? 知道如何配置了,但Spring如何知道setter方法?如何將值注入進(jìn)去的呢?其實(shí)方法名是要遵守約定的,setter注入的方法名要遵循“JavaBean getter/setter 方法命名約定”:
?
?
?
? ? ? ?JavaBean:是本質(zhì)就是一個(gè)POJO類,但具有一下限制:
? ? ? ? ?該類必須要 有公共的無(wú)參構(gòu)造器 ,如public HelloImpl4() {};
? ? ? ? ? 屬性為private訪問(wèn)級(jí)別 ,不建議public,如private String message;
? ? ? ? ? 屬性必要時(shí)通過(guò)一組setter(修改器)和getter(訪問(wèn)器)方法來(lái)訪問(wèn) ;
? ? ? ? ? setter方法,以“set”?開(kāi)頭,后跟首字母大寫的屬性名 ,如“setMesssage”,簡(jiǎn)單屬性一般只有一個(gè)方法參數(shù),方法返回值通常為“void”;
? ? ? ? ?g etter方法,一般屬性以“get”開(kāi)頭,對(duì)于boolean類型一般以“is”開(kāi)頭,后跟首字母大寫的屬性名 ,如“getMesssage”,“isOk”;
? ? ? ? ?還有一些其他特殊情況, 比如屬性有連續(xù)兩個(gè)大寫字母開(kāi)頭,如“URL”,則setter/getter方法為:“setURL”和“getURL” ,其他一些特殊情況請(qǐng)參看“Java Bean”命名規(guī)范。
?
?
3.1.4? 注入常量
?????? 注入常量是依賴注入中最簡(jiǎn)單的。配置方式如下所示:
?
- <property?name= "message" ?value= "Hello?World!" />??
- 或??
- <property?name= "index" ><value> 1 </value></property><span? class = "Apple-style-span" ?style= "font-size:?14px;?white-space:?normal;?background-color:?#ffffff;" >?</span>??
?
?????? 以上兩種方式都可以,從配置來(lái)看第一種更簡(jiǎn)潔。注意此處“value”中指定的全是字符串,由Spring容器將此字符串轉(zhuǎn)換成屬性所需要的類型,如果轉(zhuǎn)換出錯(cuò),將拋出相應(yīng)的異常。
Spring容器目前能對(duì)各種基本類型把配置的String參數(shù)轉(zhuǎn)換為需要的類型。
注:Spring類型轉(zhuǎn)換系統(tǒng)對(duì)于boolean類型進(jìn)行了容錯(cuò)處理,除了可以使用“true/false”標(biāo)準(zhǔn)的Java值進(jìn)行注入,還能使用“yes/no”、“on/off”、“1/0”來(lái)代表“真/假”,所以大家在學(xué)習(xí)或工作中遇到這種類似問(wèn)題不要覺(jué)得是人家配置錯(cuò)了,而是Spring容錯(cuò)做的非常好。
?
- 測(cè)試類??
- public ? class ?BooleanTestBean?{??
- ???? private ? boolean ?success;??
- ???? public ? void ?setSuccess( boolean ?success)?{??
- ???????? this .success?=?success;??
- ????}??
- ???? public ? boolean ?isSuccess()?{??
- ???????? return ?success;??
- ????}??
- }??
- 配置文件(chapter3/booleanInject.xml)片段:??
- <!--? boolean 參數(shù)值可以用on/off?-->??
- <bean?id= "bean2" ? class = "cn.javass.spring.chapter3.bean.BooleanTestBean" >??
- ????<property?name= "success" ?value= "on" />??
- </bean>??
- <!--? boolean 參數(shù)值可以用yes/no?-->??
- <bean?id= "bean3" ? class = "cn.javass.spring.chapter3.bean.BooleanTestBean" >??
- ????<property?name= "success" ?value= "yes" />??
- </bean>??
- <!--? boolean 參數(shù)值可以用 1 / 0 ?-->??
- <bean?id= "bean4" ? class = "cn.javass.spring.chapter3.bean.BooleanTestBean" >??
- ????<property?name= "success" ?value= "1" />??
- </bean>??
3.1.5?? ?注入Bean ID
用于注入Bean的ID,ID是一個(gè)常量不是引用,且類似于注入常量,但提供錯(cuò)誤驗(yàn)證功能,配置方式如下所示:
?
- <property?name= "id" ><idref?bean= "bean1" /></property>??
?
?
- <property?name= "id" ><idref?local= "bean2" /></property>??
?
兩種方式都可以,上述配置本質(zhì)上在運(yùn)行時(shí)等于如下方式
?
- <bean?id= "bean1" ? class = "……" />??
- <bean?id= "idrefBean1" ? class = "……" >??
- <property?name= "id" ?value?= "bean1" />??
- </bean>??
?
第一種方式可以在容器初始化時(shí)校驗(yàn)被引用的Bean是否存在,如果不存在將拋出異常,而第二種方式只有在Bean實(shí)際使用時(shí)才能發(fā)現(xiàn)傳入的Bean的ID是否正確,可能發(fā)生不可預(yù)料的錯(cuò)誤。因此如果想注入Bean的ID,推薦使用第一種方式。
接下來(lái)學(xué)習(xí)一下如何使用吧:
?
首先定義測(cè)試Bean:
?
- package ?cn.javass.spring.chapter3.bean??
- public ? class ?IdRefTestBean?{??
- ???? private ?String?id;??
- ???? public ?String?getId()?{??
- ???????? return ?id;??
- ????}??
- ???? public ? void ?setId(String?id)?{??
- ???????? this .id?=?id;??
- ????}??
- }??
?
其次定義配置文件(chapter3/idRefInject.xml):
?
- <bean?id= "bean1" ? class = "java.lang.String" >??
- <constructor-arg?index= "0" ?value= "test" />??
- </bean>??
- <bean?id= "bean2" ? class = "java.lang.String" >??
- ????<constructor-arg?index= "0" ?value= "test" />??
- </bean>??
?
?
- <bean?id= "idrefBean1" ? class = "cn.javass.spring.chapter3.bean.IdRefTestBean" >??
- ????????<property?name= "id" ><idref?bean= "bean1" /></property>??
- </bean>??
- <bean?id= "idrefBean2" ? class = "cn.javass.spring.chapter3.bean.IdRefTestBean" >??
- ????<property?name= "id" ><idref?local= "bean2" /></property>??
- </bean>??
?
?????? 從配置中可以看出,注入的Bean的ID是一個(gè)java.lang.String類型,即字符串類型,因此注入的同樣是常量,只是具有校驗(yàn)功能。
<idref bean="……"/>將在容器初始化時(shí)校驗(yàn)注入的ID對(duì)于的Bean是否存在,如果不存在將拋出異常。
<idref local="……"/>將在XML解析時(shí)校驗(yàn)注入的ID對(duì)于的Bean在當(dāng)前配置文件中是否存在,如果不存在將拋出異常,它不同于<idref bean="……"/>是校驗(yàn)發(fā)生在XML解析式而非容器初始化時(shí),且只檢查當(dāng)前配置文件中是否存在相應(yīng)的Bean。
?
3.1.6? 注入集合、數(shù)組和字典
?????? Spring不僅能注入簡(jiǎn)單類型數(shù)據(jù),還能注入集合(Collection、無(wú)序集合Set、有序集合List)類型、數(shù)組(Array)類型、字典(Map)類型數(shù)據(jù)、Properties類型數(shù)據(jù),接下來(lái)就讓我們一個(gè)個(gè)看看如何注入這些數(shù)據(jù)類型的數(shù)據(jù)。
???????一、注入集合類型: 包括Collection類型、Set類型、List類型數(shù)據(jù):
???????(1)List類型: 需要使用<list>標(biāo)簽來(lái)配置注入,其具體配置如下:
?
?????? 讓我們來(lái)寫個(gè)測(cè)試來(lái)練習(xí)一下吧:
? ? ? ? ? ? ?準(zhǔn)備測(cè)試類:
?
- package ?cn.javass.spring.chapter3.bean;??
- import ?java.util.List;??
- public ? class ?ListTestBean?{??
- ???? private ?List<String>?values;??
- ???? public ?List<String>?getValues()?{??
- ???????? return ?values;??
- ????}??
- ???? public ? void ?setValues(List<String>?values)?{??
- ???????? this .values?=?values;??
- ????}??
- }??
?
??????????????進(jìn)行Bean定義,在配置文件(resources/chapter3/listInject.xml)中配置list注入:
?
- <bean?id= "listBean" ? class = "cn.javass.spring.chapter3.bean.ListTestBean" >??
- ????<property?name= "values" >??
- ????????<list>??
- ????????????<value> 1 </value>??
- ????????????<value> 2 </value>??
- ????????????<value> 3 </value>??
- ????????</list>??
- ???</property>??
- </bean>??
?
??????????????測(cè)試代碼:
?
- @Test ??
- public ? void ?testListInject()?{??
- ???BeanFactory?beanFactory?=??
- new ?ClassPathXmlApplicationContext( "chapter3/listInject.xml" );??
- ListTestBean?listBean?=?beanFactory.getBean( "listBean" ,?ListTestBean. class );??
- System.out.println(listBean.getValues().size());??
- Assert.assertEquals( 3 ,?listBean.getValues().size());??
- }??
?
?
(2)Set類型: 需要使用<set>標(biāo)簽來(lái)配置注入,其配置參數(shù)及含義和<lsit>標(biāo)簽完全一樣,在此就不闡述了:
? ? ? ? ? ? ? 準(zhǔn)備測(cè)試類:
?
- package ?cn.javass.spring.chapter3.bean;??
- import ?java.util.Collection;??
- public ? class ?CollectionTestBean?{??
- ???? private ?Collection<String>?values;??
- ???? public ? void ?setValues(Collection<String>?values)?{??
- ???????? this .values?=?values;??
- ????}??
- ???? public ?Collection<String>?getValues()?{??
- ???????? return ?values;??
- ????}??
- }??
? ? ? ? ? ??
??????????????進(jìn)行Bean定義,在配置文件(resources/chapter3/listInject.xml)中配置list注入:
?
- <bean?id= "setBean" ? class = "cn.javass.spring.chapter3.bean.SetTestBean" >??
- <property?name= "values" >??
- <set>??
- <value> 1 </value>??
- <value> 2 </value>??
- <value> 3 </value>??
- </set>??
- </property>??
- </bean>??
? ? ? ? ? ? ? 具體測(cè)試代碼就不寫了,和listBean測(cè)試代碼完全一樣。
?
??????? (2)Collection類型: 因?yàn)镃ollection類型是Set和List類型的基類型,所以使用<set>或<list>標(biāo)簽都可以進(jìn)行注入,配置方式完全和以上配置方式一樣,只是將測(cè)試類屬性改成“Collection”類型,如果配置有問(wèn)題,可參考cn.javass.spring.chapter3.DependencyInjectTest測(cè)試類中的testCollectionInject測(cè)試方法中的代碼。
二、 注入數(shù)組類型 :需要使用<array>標(biāo)簽來(lái)配置注入,其中標(biāo)簽屬性“value-type”和“merge”和<list>標(biāo)簽含義完全一樣,具體配置如下:
?
?????? 如果練習(xí)時(shí)遇到配置問(wèn)題,可以參考“cn.javass.spring.chapter3.DependencyInjectTest”測(cè)試類中的testArrayInject測(cè)試方法中的代碼。
?
???????三、注入字典(Map)類型: 字典類型是包含鍵值對(duì)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),需要使用<map>標(biāo)簽來(lái)配置注入,其屬性“key-type”和“value-type”分別指定“鍵”和“值”的數(shù)據(jù)類型,其含義和<list>標(biāo)簽的“value-type”含義一樣,在此就不羅嗦了,并使用<key>子標(biāo)簽來(lái)指定鍵數(shù)據(jù),<value>子標(biāo)簽來(lái)指定鍵對(duì)應(yīng)的值數(shù)據(jù),具體配置如下:
?
?????? 如果練習(xí)時(shí)遇到配置問(wèn)題,可以參考“cn.javass.spring.chapter3.DependencyInjectTest”測(cè)試類中的testMapInject測(cè)試方法中的代碼。
四、 Properties注入 :Spring能注入java.util.Properties類型數(shù)據(jù),需要使用<props>標(biāo)簽來(lái)配置注入,鍵和值類型必須是String,不能變,子標(biāo)簽<prop key=”鍵”>值</prop>來(lái)指定鍵值對(duì),具體配置如下:
?
?
如果練習(xí)時(shí)遇到配置問(wèn)題,可以參考cn.javass.spring.chapter3.DependencyInjectTest測(cè)試類中的testPropertiesInject測(cè)試方法中的代碼。
?????? 到此我們已經(jīng)把簡(jiǎn)單類型及集合類型介紹完了,大家可能會(huì)問(wèn)怎么沒(méi)見(jiàn)注入“Bean之間關(guān)系”的例子呢?接下來(lái)就讓我們來(lái)講解配置Bean之間依賴關(guān)系,也就是注入依賴Bean。
?
??
?
3.1.7? 引用其它Bean
?????? 上邊章節(jié)已經(jīng)介紹了注入常量、集合等基本數(shù)據(jù)類型和集合數(shù)據(jù)類型,本小節(jié)將介紹注入依賴Bean及注入內(nèi)部Bean。
?????? 引用其他Bean的步驟與注入常量的步驟一樣,可以通過(guò)構(gòu)造器注入及setter注入引用其他Bean,只是引用其他Bean的注入配置稍微變化了一下:可以將“<constructor-arg index="0" value="Hello World!"/>”和“<property name="message" value="Hello World!"/>”中的value屬性替換成bean屬性,其中bean屬性指定配置文件中的其他Bean的id或別名。另一種是把<value>標(biāo)簽替換為<.ref bean=”beanName”>,bean屬性也是指定配置文件中的其他Bean的id或別名。那讓我們看一下具體配置吧:
?
一、構(gòu)造器注入方式:
(1)通過(guò)” <constructor-arg>”標(biāo)簽的ref屬性來(lái)引用其他Bean,這是最簡(jiǎn)化的配置:
?
(2)通過(guò)” <constructor-arg>”標(biāo)簽的子<ref>標(biāo)簽來(lái)引用其他Bean,使用bean屬性來(lái)指定引用的Bean:
?
???????二、setter注入方式:
(1)通過(guò)” <property>”標(biāo)簽的ref屬性來(lái)引用其他Bean,這是最簡(jiǎn)化的配置:
?
(2)通過(guò)” <property>”標(biāo)簽的子<ref>標(biāo)簽來(lái)引用其他Bean,使用bean屬性來(lái)指定引用的Bean:
?
?
三、接下來(lái)讓我們用個(gè)具體例子來(lái)講解一下具體使用吧:
(1)首先讓我們定義測(cè)試引用Bean的類,在此我們可以使用原有的HelloApi實(shí)現(xiàn),然后再定義一個(gè)裝飾器來(lái)引用其他Bean,具體裝飾類如下:
?
- package ?cn.javass.spring.chapter3.bean;??
- import ?cn.javass.spring.chapter2.helloworld.HelloApi;??
- public ? class ?HelloApiDecorator? implements ?HelloApi?{??
- private ?HelloApi?helloApi;??
- //空參構(gòu)造器 ??
- ???? public ?HelloApiDecorator()?{??
- }??
- //有參構(gòu)造器 ??
- ???? public ?HelloApiDecorator(HelloApi?helloApi)?{??
- ???????? this .helloApi?=?helloApi;??
- }????
- public ? void ?setHelloApi(HelloApi?helloApi)?{??
- ???????? this .helloApi?=?helloApi;??
- ????}??
- ???? @Override ??
- ???? public ? void ?sayHello()?{??
- ????????System.out.println( "==========裝飾一下===========" );??
- ????????helloApi.sayHello();??
- ????????System.out.println( "==========裝飾一下===========" );??
- ????}??
- }??
?
?????? (2)定義好了測(cè)試引用Bean接下來(lái)該在配置文件(resources/chapter3/beanInject.xml)進(jìn)行配置Bean定義了,在此將演示通過(guò)構(gòu)造器及setter方法方式注入依賴Bean:
??????
- <!--?定義依賴Bean?-->??
- <bean?id= "helloApi" ? class = "cn.javass.spring.chapter2.helloworld.HelloImpl" />??
- <!--?通過(guò)構(gòu)造器注入?-->??
- <bean?id= "bean1" ? class = "cn.javass.spring.chapter3.bean.HelloApiDecorator" >??
- <constructor-arg?index= "0" ?ref= "helloApi" />??
- </bean>??
- <!--?通過(guò)構(gòu)造器注入?-->??
- <bean?id= "bean2" ? class = "cn.javass.spring.chapter3.bean.HelloApiDecorator" >??
- ????<property?name= "helloApi" ><ref?bean= "?helloApi" /></property>??
- </bean>??
?
?
(3)測(cè)試一下吧,測(cè)試代碼(cn.javass.spring.chapter3.DependencyInjectTest)片段如下:
?
- @Test ??
- public ? void ?testBeanInject()?{??
- ????BeanFactory?beanFactory?=??
- new ?ClassPathXmlApplicationContext( "chapter3/beanInject.xml" );??
- ???? //通過(guò)構(gòu)造器方式注入 ??
- ????HelloApi?bean1?=?beanFactory.getBean( "bean1" ,?HelloApi. class );??
- ????bean1.sayHello();??
- ???? //通過(guò)setter方式注入 ??
- ????HelloApi?bean2?=?beanFactory.getBean( "bean2" ,?HelloApi. class );??
- ????bean2.sayHello();??
- }??
?
???????四、其他引用方式: 除了最基本配置方式以外,Spring還提供了另外兩種更高級(jí)的配置方式,<ref local=””/>和<ref parent=””/> :
??????? (1)<ref local=””/>配置方式:用于引用通過(guò)<bean id=”beanName”>方式中通過(guò)id屬性指定的Bean,它能利用XML解析器的驗(yàn)證功能在讀取配置文件時(shí)來(lái)驗(yàn)證引用的Bean是否存在。因此如果在當(dāng)前配置文件中有相互引用的Bean可以采用<ref local>方式從而如果配置錯(cuò)誤能在開(kāi)發(fā)調(diào)試時(shí)就發(fā)現(xiàn)錯(cuò)誤。
如果引用一個(gè)在當(dāng)前配置文件中不存在的Bean將拋出如下異常:
org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException: Line21 inXML document from class path resource [chapter3/beanInject2.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-id.1: There is no ID/IDREF binding for IDREF 'helloApi'.
<ref local>具體配置方式如下:
?
?????? (2)<ref parent=””/>配置方式:用于引用父容器中的Bean,不會(huì)引用當(dāng)前容器中的Bean,當(dāng)然父容器中的Bean和當(dāng)前容器的Bean是可以重名的,獲取順序是先查找當(dāng)前容器中的Bean,如果找不到再?gòu)母溉萜髡摇>唧w配置方式如下:
接下來(lái)讓我們用個(gè)例子演示一下<ref local>和<ref parent>的配置過(guò)程:
首先還是準(zhǔn)備測(cè)試類,在此我們就使用以前寫好的HelloApiDecorator和HelloImpl4類;其次進(jìn)行Bean定義,其中當(dāng)前容器bean1引用本地的”helloApi”,而”bean2”將引用父容器的”helloApi”,配置如下:
?
- <!--?sources/chapter3/parentBeanInject.xml表示父容器配置-->??
- <!--注意此處可能子容器也定義一個(gè)該Bean-->??
- <bean?id= "helloApi" ? class = "cn.javass.spring.chapter3.HelloImpl4" >??
- <property?name= "index" ?value= "1" />??
- <property?name= "message" ?value= "Hello?Parent!" />??
- </bean>??
?
?
- <!--?sources/chapter3/localBeanInject.xml表示當(dāng)前容器配置-->??
- <!--?注意父容器中也定義了id?為?helloApi的Bean?-->??
- <bean?id= "helloApi" ? class = "cn.javass.spring.chapter3.HelloImpl4" >??
- <property?name= "index" ?value= "1" />??
- ????<property?name= "message" ?value= "Hello?Local!" />??
- </bean>??
- <!--?通過(guò)local注入?-->??
- <bean?id= "bean1" ? class = "cn.javass.spring.chapter3.bean.HelloApiDecorator" >??
- <constructor-arg?index= "0" ><ref?local= "helloApi" /></constructor-arg>??
- </bean>??
- <!--?通過(guò)parent注入?-->??
- <bean?id= "bean2" ? class = "cn.javass.spring.chapter3.bean.HelloApiDecorator" >??
- <property?name= "helloApi" ><ref?parent= "helloApi" /></property>??
- </bean>??
?
(3)寫測(cè)試類測(cè)試一下吧,具體代碼片段如下:?
?
- @Test ??
- public ? void ?testLocalAndparentBeanInject()?{??
- //初始化父容器 ??
- ApplicationContext?parentBeanContext?=??
- new ?ClassPathXmlApplicationContext( "chapter3/parentBeanInject.xml" );??
- //初始化當(dāng)前容器 ??
- ApplicationContext?beanContext?=? new ?ClassPathXmlApplicationContext(??
- new ?String[]?{ "chapter3/localBeanInject.xml" },?parentBeanContext);??
- ????HelloApi?bean1?=?beanContext.getBean( "bean1" ,?HelloApi. class );??
- ????bean1.sayHello(); //該Bean引用local?bean ??
- HelloApi?bean2?=?beanContext.getBean( "bean2" ,?HelloApi. class );??
- bean2.sayHello(); //該Bean引用parent?bean ??
- }??
?
?“bean1”將輸出“Hello Local!”表示引用當(dāng)前容器的Bean,”bean2”將輸出“Hello Paren!”,表示引用父容器的Bean,如配置有問(wèn)題請(qǐng)參考cn.javass.spring.chapter3.DependencyInjectTest中的testLocalAndparentBeanInject測(cè)試方法。
?
3.1.8? 內(nèi)部Bean定義
內(nèi)部Bean就是在<property>或<constructor-arg>內(nèi)通過(guò)<bean>標(biāo)簽定義的Bean,該Bean不管是否指定id或name,該Bean都會(huì)有唯一的匿名標(biāo)識(shí)符,而且不能指定別名,該內(nèi)部Bean對(duì)其他外部Bean不可見(jiàn),具體配置如下:
?
(1)讓我們寫個(gè)例子測(cè)試一下吧,具體配置文件如下:
?
- <bean?id= "bean" ? class = "cn.javass.spring.chapter3.bean.HelloApiDecorator" >??
- <property?name= "helloApi" >??
- <bean?id= "helloApi" ? class = "cn.javass.spring.chapter2.helloworld.HelloImpl" />??
- </property>??
- </bean>??
?
?
?(2)測(cè)試代碼(cn.javass.spring.chapter3.DependencyInjectTest.testInnerBeanInject):
?
- @Test ??
- public ? void ?testInnerBeanInject()?{??
- ApplicationContext?context?=??
- new ?ClassPathXmlApplicationContext( "chapter3/innerBeanInject.xml" );??
- HelloApi?bean?=?context.getBean( "bean" ,?HelloApi. class );??
- bean.sayHello();??
- }??
?
3.1.9? 處理null值
?????? ?Spring通過(guò)<value>標(biāo)簽或value屬性注入常量值,所有注入的數(shù)據(jù)都是字符串,那如何注入null值呢?通過(guò)“null”值嗎?當(dāng)然不是因?yàn)槿绻⑷搿皀ull”則認(rèn)為是字符串。Spring通過(guò)<null/>標(biāo)簽注入null值。即可以采用如下配置方式:
?
3.1.10 對(duì)象圖導(dǎo)航注入支持
?????? 所謂對(duì)象圖導(dǎo)航是指類似a.b.c這種點(diǎn)綴訪問(wèn)形式的訪問(wèn)或修改值。Spring支持對(duì)象圖導(dǎo)航方式依賴注入。對(duì)象圖導(dǎo)航依賴注入有一個(gè)限制就是比如a.b.c對(duì)象導(dǎo)航圖注入中a和b必須為非null值才能注入c,否則將拋出空指針異常。
?????? Spring不僅支持對(duì)象的導(dǎo)航,還支持?jǐn)?shù)組、列表、字典、Properties數(shù)據(jù)類型的導(dǎo)航,對(duì)Set數(shù)據(jù)類型無(wú)法支持,因?yàn)闊o(wú)法導(dǎo)航。
數(shù)組和列表數(shù)據(jù)類型可以用array[0]、list[1]導(dǎo)航,注意”[]”里的必須是數(shù)字,因?yàn)槭前凑账饕M(jìn)行導(dǎo)航,對(duì)于數(shù)組類型注意不要數(shù)組越界錯(cuò)誤。
字典Map數(shù)據(jù)類型可以使用map[1]、map[str]進(jìn)行導(dǎo)航,其中“[]”里的是基本類型,無(wú)法放置引用類型。
?????? 讓我們來(lái)練習(xí)一下吧。首先準(zhǔn)備測(cè)試類,在此我們需要三個(gè)測(cè)試類,以便實(shí)現(xiàn)對(duì)象圖導(dǎo)航功能演示:
?????? ?NavigationC類用于打印測(cè)試代碼,從而觀察配置是否正確;具體類如下所示:
?
- package ?cn.javass.spring.chapter3.bean;??
- public ? class ?NavigationC?{??
- ???? public ? void ?sayNavigation()?{??
- ????????System.out.println( "===navigation?c" );??
- ????}??
- }??
?
?? ?NavigationB類,包含對(duì)象和列表、Properties、數(shù)組字典數(shù)據(jù)類型導(dǎo)航,而且這些復(fù)合數(shù)據(jù)類型保存的條目都是對(duì)象,正好練習(xí)一下如何往復(fù)合數(shù)據(jù)類型中注入對(duì)象依賴。具體類如下所示:
?
?
- package ?cn.javass.spring.chapter3.bean;??
- import ?java.util.List;??
- import ?java.util.Map;??
- import ?java.util.Properties;??
- public ? class ?NavigationB?{??
- ???? private ?NavigationC?navigationC;??
- ???? private ?List<NavigationC>?list;??
- ???? private ?Properties?properties;??
- ???? private ?NavigationC[]?array?=? new ?NavigationC[ 1 ];??
- ???? private ?Map<String,?NavigationC>?map;??
- ??? //由于setter和getter方法占用太多空間,故省略,大家自己實(shí)現(xiàn)吧 ??
- }??
?
?????? ?NavigationA類是我們的前端類,通過(guò)對(duì)它的導(dǎo)航進(jìn)行注入值,具體代碼如下:
?
- package ?cn.javass.spring.chapter3.bean;??
- public ? class ?NavigationA?{??
- ???? private ?NavigationB?navigationB;??
- ???? public ? void ?setNavigationB(NavigationB?navigationB)?{??
- ???????? this .navigationB?=?navigationB;??
- ????}??
- ???? public ?NavigationB?getNavigationB()?{??
- ???????? return ?navigationB;??
- ????}??
- }??
?
?????? ?接下來(lái)該進(jìn)行Bean定義配置(resources/chapter3/navigationBeanInject.xml)了,首先讓我們配置一下需要被導(dǎo)航的數(shù)據(jù),NavigationC和NavigationB類,其中配置NavigationB時(shí)注意要確保比如array字段不為空值,這就需要或者在代碼中賦值如“NavigationC[] array = new NavigationC[1];”,或者通過(guò)配置文件注入如“<list></list>”注入一個(gè)不包含條目的列表。具體配置如下:
?
- <bean?id= "c" ? class = "cn.javass.spring.chapter3.bean.NavigationC" />??
- <bean?id= "b" ? class = "cn.javass.spring.chapter3.bean.NavigationB" >??
- <property?name= "list" ><list></list></property>??
- ????<property?name= "map" ><map></map></property>??
- ????<property?name= "properties" ><props></props></property>??
- </bean>??
?
?????? ? 配置完需要被導(dǎo)航的Bean定義了,該來(lái)配置NavigationA導(dǎo)航Bean了,在此需要注意,由于“navigationB”屬性為空值,在此需要首先注入“navigationB”值;還有對(duì)于數(shù)組導(dǎo)航不能越界否則報(bào)錯(cuò);具體配置如下:
?
- <bean?id= "a" ? class = "cn.javass.spring.chapter3.bean.NavigationA" >??
- <!--?首先注入navigatiionB?確保它非空?-->??
- <property?name= "navigationB" ?ref= "b" />??
- <!--?對(duì)象圖導(dǎo)航注入?-->??
- <property?name= "navigationB.navigationC" ?ref= "c" />??
- <!--?注入列表數(shù)據(jù)類型數(shù)據(jù)?-->??
- <property?name= "navigationB.list[0]" ?ref= "c" />??
- <!--?注入map類型數(shù)據(jù)?-->??
- <property?name= "navigationB.map[key]" ?ref= "c" />??
- <!--?注入properties類型數(shù)據(jù)?-->??
- <property?name= "navigationB.properties[0]" ?ref= "c" />??
- <!--?注入properties類型數(shù)據(jù)?-->??
- <property?name= "navigationB.properties[1]" ?ref= "c" />??
- <!--?注入數(shù)組類型數(shù)據(jù)?,注意不要越界-->??
- <property?name= "navigationB.array[0]" ?ref= "c" />??
- </bean>??
- ???
?????? ?配置完畢,具體測(cè)試代碼在cn.javass.spring.chapter3. DependencyInjectTest,讓我們看下測(cè)試代碼吧:
?
- //對(duì)象圖導(dǎo)航 ??
- @Test ??
- public ? void ?testNavigationBeanInject()?{??
- ApplicationContext?context?=??
- new ?ClassPathXmlApplicationContext( "chapter3/navigationBeanInject.xml" );?????????
- NavigationA?navigationA?=?context.getBean( "a" ,?NavigationA. class );??
- navigationA.getNavigationB().getNavigationC().sayNavigation();??
- navigationA.getNavigationB().getList().get( 0 ).sayNavigation();??
- navigationA.getNavigationB().getMap().get( "key" ).sayNavigation();??
- navigationA.getNavigationB().getArray()[ 0 ].sayNavigation();??
- ((NavigationC)navigationA.getNavigationB().getProperties().get( "1" ))??
- .sayNavigation();?????????
- }??
- ???
?
?????? 測(cè)試完畢,應(yīng)該輸出5個(gè)“===navigation c”,是不是很簡(jiǎn)單,注意這種方式是不推薦使用的,了解一下就夠了,最好使用3.1.5一節(jié)使用的配置方式。
?????? ??????
3.1.11配置簡(jiǎn)寫
讓我們來(lái)總結(jié)一下依賴注入配置及簡(jiǎn)寫形式,其實(shí)我們已經(jīng)在以上部分穿插著進(jìn)行簡(jiǎn)化配置了:
?
一、構(gòu)造器注入:
1)常量值
簡(jiǎn)寫:<constructor-arg index="0" value="常量"/>
全寫:<constructor-arg index="0"><value>常量</value></constructor-arg>
2)引用
簡(jiǎn)寫:<constructor-arg index="0" ref="引用"/>
全寫:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>
?
二、setter注入: ??????
?????? 1)常量值
?????? ?簡(jiǎn)寫:<property name="message" value="常量"/>
? ? ? ? 全寫:<property name="message"><value>常量</value></ property>
?????? 2)引用
?????? ?簡(jiǎn)寫:<property name="message" ref="引用"/>
? ? ? ? 全寫:<property name="message"><ref bean="引用"/></ property>
?????? 3)數(shù)組:<array>沒(méi)有簡(jiǎn)寫形式
?????? 4)列表:<list>沒(méi)有簡(jiǎn)寫形式
?????? 5)集合:<set>沒(méi)有簡(jiǎn)寫形式
?????? 6)字典
? ? ? ? ? 簡(jiǎn)寫:<map>
???????????? <entry key="鍵常量" value="值常量"/>
???????????? <entry key-ref="鍵引用" value-ref="值引用"/>
??????????? </map>
? ? ? ? ?全寫:<map>
???????????? <entry><key><value>鍵常量</value></key><value>值常量</value></entry>
???????????? <entry><key><ref bean="鍵引用"/></key><ref bean="值引用"/></entry>
?????????? </map>
?????? 7)Properties:沒(méi)有簡(jiǎn)寫形式
?
三、使用p命名空間簡(jiǎn)化setter注入:
?????? 使用p命名空間來(lái)簡(jiǎn)化setter注入,具體使用如下:
?????????????
?
- <?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" ??
- ????????xsi:schemaLocation="??
- ???????????http: //www.springframework.org/schema/beans ??
- ???????????http: //www.springframework.org/schema/beans/spring-beans-3.0.xsd"> ??
- <bean?id= "bean1" ? class = "java.lang.String" >??
- ????????<constructor-arg?index= "0" ?value= "test" />??
- ????</bean>??
- <bean?id= "idrefBean1" ? class = "cn.javass.spring.chapter3.bean.IdRefTestBean" ??
- p:id= "value" />??
- <bean?id= "idrefBean2" ? class = "cn.javass.spring.chapter3.bean.IdRefTestBean" ??
- p:id-ref= "bean1" />??
- </beans>??
- xmlns:p="http://www.springframework.org/schema/p"?:首先指定p命名空間;
-
<bean id="……" class="……" p:id="value"/>?:
常量setter注入方式,其等價(jià)于<property name="id" value="value"/>;
- <bean id="……" class="……" p:id-ref="bean1"/>?: 引用setter注入方式,其等價(jià)于<property name="id" ref="bean1"/>。?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
