3.1 依賴和依賴注入
依賴注入帶來的好處:
動(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ì)象完成的功能李皇,通過容器注入依賴實(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沒有依賴Bean,而是采用繼承方式添加新功能篡殷,钝吮,而且功能是在編譯時(shí)就確定了,不具有動(dòng)態(tài)性板辽,而且采用類繼承導(dǎo)致Bean與子Bean之間高度耦合搀绣,難以復(fù)用。
增加Bean可復(fù)用性:依賴于對(duì)象組合戳气,Bean更可復(fù)用且復(fù)用更簡(jiǎn)單;
降低Bean之間耦合:由于我們完全采用面向接口編程巧鸭,在代碼中沒有直接引用Bean依賴實(shí)現(xiàn)瓶您,全部引用接口,而且不會(huì)出現(xiàn)顯示的創(chuàng)建依賴對(duì)象代碼纲仍,而且這些依賴是由容器來注入呀袱,很容易替換依賴實(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容器也注入不了任何東西,從而從根本上說“如何設(shè)計(jì)好類結(jié)構(gòu)才是關(guān)鍵细办,依賴注入只是一種裝配對(duì)象手段”橙凳。
前邊IoC一章我們已經(jīng)了解了Bean依賴容器,那容器如何注入Bean的依賴資源笑撞,Spring IoC容器注入依賴資源主要有以下兩種基本實(shí)現(xiàn)方式:
構(gòu)造器注入:就是容器實(shí)例化Bean時(shí)注入那些依賴岛啸,通過在在Bean定義中指定構(gòu)造器參數(shù)進(jìn)行注入依賴,包括實(shí)例工廠方法參數(shù)注入依賴茴肥,但靜態(tài)工廠方法參數(shù)不允許注入依賴坚踩;
setter注入:通過setter方法進(jìn)行注入依賴;
方法注入:能通過配置方式替換掉Bean方法炉爆,也就是通過配置改變Bean方法 功能堕虹。
3.1.2 注入方式
構(gòu)造器注入:通過配置構(gòu)造參數(shù)實(shí)現(xiàn),構(gòu)造參數(shù)就是依賴芬首。處理構(gòu)造方式赴捞,還可以通靜態(tài)工廠,實(shí)例工廠方法進(jìn)行構(gòu)造器注入
一郁稍、根據(jù)參數(shù)索引注入赦政,使用標(biāo)簽“<constructor-arg index="1" value="1"/>”來指定注入的依賴,其中“index”表示索引耀怜,從0開始恢着,即第一個(gè)參數(shù)索引為0,“value”來指定注入的常量值财破,配置方式如下:
二掰派、根據(jù)參數(shù)類型進(jìn)行注入,使用標(biāo)簽“<constructor-arg type="java.lang.String" value="Hello World!"/>”來指定注入的依賴左痢,其中“type”表示需要匹配的參數(shù)類型靡羡,可以是基本類型也可以是其他類型,如“int”俊性、“java.lang.String”略步,“value”來指定注入的常量值,配置方式如下:
三定页、根據(jù)參數(shù)名進(jìn)行注入趟薄,使用標(biāo)簽“<constructor-arg name="message" value="Hello World!"/>”來指定注入的依賴,其中“name”表示需要匹配的參數(shù)名字典徊,“value”來指定注入的常量值杭煎,配置方式如下
以下為測(cè)試類:
3.1.3 setter注入:通過構(gòu)造器恩够,靜態(tài)工廠和實(shí)例工廠實(shí)例化bean后,調(diào)用bean的setter方法進(jìn)行注入依賴
屬性為private訪問級(jí)別岔帽,不建議public玫鸟,如private String message;
屬性必要時(shí)通過一組setter(修改器)和getter(訪問器)方法來訪問;
配置方式:
準(zhǔn)備測(cè)試類進(jìn)行測(cè)試
3.1.4常量注入
<property name="userName" value="sssssss"/>
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”來代表“真/假”,所以大家在學(xué)習(xí)或工作中遇到這種類似問題不要覺得是人家配置錯(cuò)了导犹,而是Spring容錯(cuò)做的非常好唱凯。
3.1.5 注入集合 set 數(shù)組
注入集合配置
private List<String> list;
配置文件:
<bean id="setBean1" class="test.spring.DI.HelloServiceImpl">
? ? <property name="list">
? ? ? ? <list value-type="java.lang.String" merge="default">
? ? ? ? ? ? <value>1
? ? ? ? ? ? <value>2
? ? ? ? ? ? <value>3
</bean>
set注入:
Collection類型:因?yàn)镃ollection類型是Set和List類型的基類型,所以使用或標(biāo)簽都可以進(jìn)行注入谎痢,配置方式完全和以上配置方式一樣
private Collection?col;
<bean id="setBean1" class="test.spring.DI.HelloServiceImpl">
? ? <property name="col">
? ? ? ? ? ? <value>4
? ? ? ? ? ? <value>5
? ? ? ? ? ? <value>6
</bean>
數(shù)組注入:
private String [] array;
private String [][] array1;
<bean id="setBean1" class="test.spring.DI.HelloServiceImpl">
? ? <property name="array">
? ? ? ? <array value-type="java.lang.String" merge="default">
? ? ? ? ? ? <value>1
? ? ? ? ? ? <value>2
? ? ? ? ? ? <value>3
? ? <property name="array1">
? ? ? ? ? ? ? ? <value>1
? ? ? ? ? ? ? ? <value>2
? ? ? ? ? ? ? ? <value>3
? ? ? ? ? ? ? ? <value>4
? ? ? ? ? ? ? ? <value>5
</bean>
注入map類型:
private Map<String,String> map;
<property name="map">
? ? <map value-type="java.lang.String" key-type="java.lang.String">
? ? ? ? ? ? <key><value>1
? ? ? ? ? ? <value>2
? ? ? ? <entry key="2" value="3"/>
</property>
然后開始編寫測(cè)試類進(jìn)行測(cè)試:
public class HelloServiceImplimplements HelloApi{
private StringuserName;
? ? private Integerindex;
? ? private Listlist;
? ? private Collectioncol;
? ? private Mapmap;
? ? private Propertiespro;
? ? private String []array;
? ? private String [][]array1;
? ? @Override
? ? public void sayHello() {
System.out.println("index:" +index +", userName:" +userName);
? ? ? ? for (String str :list) {
System.out.print("list:" + str);
? ? ? ? }
System.out.println("");
? ? ? ? for (String c :col) {
System.out.print("set:" + c);
? ? ? ? }
System.out.println("");
? ? ? ? for (String s :map.keySet()) {
System.out.print("map:" +map.get(s) +",");
? ? ? ? }
System.out.println("");
? ? }
......省略setter方法
}
測(cè)試類:
@Test
public void test(){
BeanFactory factory =new ClassPathXmlApplicationContext("com/comverse/timesheet/config/dispatcher-servlet.xml");
? ? HelloApi helloApi = factory.getBean("setBean", HelloApi.class);
? ? helloApi.sayHello();
}
總結(jié):
一磕昼、構(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>沒有簡(jiǎn)寫形式
?????? 4)列表:<list>沒有簡(jiǎn)寫形式
?????? 5)集合:<set>沒有簡(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:沒有簡(jiǎn)寫形式
使用p命名空間簡(jiǎn)化setter注入:
xmlns:p="http://www.springframework.org/schema/p"?:首先指定p命名空間节猿;
<bean id="……" class="……" p:id="value"/>?:常量setter注入方式票从,其等價(jià)于;
<bean id="……" class="……" p:id-ref="bean1"/>?:引用setter注入方式滨嘱,其等價(jià)于