3.1 依賴和依賴注入
依賴注入帶來的好處:
動態(tài)替換Bean依賴對象,程序更靈活:替換Bean依賴對象,無需修改源文件:應(yīng)用依賴注入后,由于可以采用配置文件方式實現(xiàn),從而能隨時動態(tài)的替換Bean的依賴對象,無需修改java源文件;
更好實踐面向接口編程,代碼更清晰:在Bean中只需指定依賴對象的接口,接口定義依賴對象完成的功能,通過容器注入依賴實現(xiàn);
更好實踐優(yōu)先使用對象組合,而不是類繼承:因為IoC容器采用注入依賴,也就是組合對象,從而更好的實踐對象組合。
采用對象組合,Bean的功能可能由幾個依賴Bean的功能組合而成,其Bean本身可能只提供少許功能或根本無任何功能,全部委托給依賴Bean,對象組合具有動態(tài)性,能更方便的替換掉依賴Bean,從而改變Bean功能;
而如果采用類繼承,Bean沒有依賴Bean,而是采用繼承方式添加新功能,,而且功能是在編譯時就確定了,不具有動態(tài)性,而且采用類繼承導致Bean與子Bean之間高度耦合,難以復用。
增加Bean可復用性:依賴于對象組合,Bean更可復用且復用更簡單;
降低Bean之間耦合:由于我們完全采用面向接口編程,在代碼中沒有直接引用Bean依賴實現(xiàn),全部引用接口,而且不會出現(xiàn)顯示的創(chuàng)建依賴對象代碼,而且這些依賴是由容器來注入,很容易替換依賴實現(xiàn)類,從而降低Bean與依賴之間耦合;
代碼結(jié)構(gòu)更清晰:要應(yīng)用依賴注入,代碼結(jié)構(gòu)要按照規(guī)約方式進行書寫,從而更好的應(yīng)用一些最佳實踐,因此代碼結(jié)構(gòu)更清晰。
從以上我們可以看出,其實依賴注入只是一種裝配對象的手段,設(shè)計的類結(jié)構(gòu)才是基礎(chǔ),如果設(shè)計的類結(jié)構(gòu)不支持依賴注入,Spring IoC容器也注入不了任何東西,從而從根本上說“如何設(shè)計好類結(jié)構(gòu)才是關(guān)鍵,依賴注入只是一種裝配對象手段”。
前邊IoC一章我們已經(jīng)了解了Bean依賴容器,那容器如何注入Bean的依賴資源,Spring IoC容器注入依賴資源主要有以下兩種基本實現(xiàn)方式:
構(gòu)造器注入:就是容器實例化Bean時注入那些依賴,通過在在Bean定義中指定構(gòu)造器參數(shù)進行注入依賴,包括實例工廠方法參數(shù)注入依賴,但靜態(tài)工廠方法參數(shù)不允許注入依賴;
setter注入:通過setter方法進行注入依賴;
方法注入:能通過配置方式替換掉Bean方法,也就是通過配置改變Bean方法 功能。
3.1.2 注入方式
構(gòu)造器注入:通過配置構(gòu)造參數(shù)實現(xiàn),構(gòu)造參數(shù)就是依賴。處理構(gòu)造方式,還可以通靜態(tài)工廠,實例工廠方法進行構(gòu)造器注入
一、根據(jù)參數(shù)索引注入,使用標簽“<constructor-arg index="1" value="1"/>”來指定注入的依賴,其中“index”表示索引,從0開始,即第一個參數(shù)索引為0,“value”來指定注入的常量值,配置方式如下:

二、根據(jù)參數(shù)類型進行注入,使用標簽“<constructor-arg type="java.lang.String" value="Hello World!"/>”來指定注入的依賴,其中“type”表示需要匹配的參數(shù)類型,可以是基本類型也可以是其他類型,如“int”、“java.lang.String”,“value”來指定注入的常量值,配置方式如下:

三、根據(jù)參數(shù)名進行注入,使用標簽“<constructor-arg name="message" value="Hello World!"/>”來指定注入的依賴,其中“name”表示需要匹配的參數(shù)名字,“value”來指定注入的常量值,配置方式如下

以下為測試類:


3.1.3 setter注入:通過構(gòu)造器,靜態(tài)工廠和實例工廠實例化bean后,調(diào)用bean的setter方法進行注入依賴
屬性為private訪問級別,不建議public,如private String message;
屬性必要時通過一組setter(修改器)和getter(訪問器)方法來訪問;
配置方式:

準備測試類進行測試


3.1.4常量注入
<property name="userName" value="sssssss"/>
Spring容器將此字符串轉(zhuǎn)換成屬性所需要的類型,如果轉(zhuǎn)換出錯,將拋出相應(yīng)的異常。
Spring容器目前能對各種基本類型把配置的String參數(shù)轉(zhuǎn)換為需要的類型。
注:Spring類型轉(zhuǎn)換系統(tǒng)對于boolean類型進行了容錯處理,除了可以使用“true/false”標準的Java值進行注入,還能使用“yes/no”、“on/off”、“1/0”來代表“真/假”,所以大家在學習或工作中遇到這種類似問題不要覺得是人家配置錯了,而是Spring容錯做的非常好。
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類型:因為Collection類型是Set和List類型的基類型,所以使用或標簽都可以進行注入,配置方式完全和以上配置方式一樣
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>
然后開始編寫測試類進行測試:
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方法
}
測試類:
@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)常量值
簡寫:<constructor-arg index="0" value="常量"/>
全寫:<constructor-arg index="0"><value>常量</value></constructor-arg>
2)引用
簡寫:<constructor-arg index="0" ref="引用"/>
全寫:<constructor-arg index="0"><ref bean="引用"/></constructor-arg>
二、setter注入:
?????? 1)常量值
?????? ?簡寫:<property name="message" value="常量"/>
? ? ? ? 全寫:<property name="message"><value>常量</value></ property>
?????? 2)引用
?????? ?簡寫:<property name="message" ref="引用"/>
? ? ? ? 全寫:<property name="message"><ref bean="引用"/></ property>
?????? 3)數(shù)組:<array>沒有簡寫形式
?????? 4)列表:<list>沒有簡寫形式
?????? 5)集合:<set>沒有簡寫形式
?????? 6)字典
? ? ? ? ? 簡寫:<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:沒有簡寫形式
使用p命名空間簡化setter注入:
xmlns:p="http://www.springframework.org/schema/p"?:首先指定p命名空間;
<bean id="……" class="……" p:id="value"/>?:常量setter注入方式,其等價于;
<bean id="……" class="……" p:id-ref="bean1"/>?:引用setter注入方式,其等價于