srping基础——DI(三)
1、依賴和依賴注入
傳統應用程序設計中所說的依賴一般指的是“類與類之間的關系”,那么首先讓我們復習一下類之間的關系:
泛化:表示類與類之間的繼承關系,表示接口與接口之間的繼承關系;
實現:表示類對接口的實現;
依賴:當類與類之間有使用關系時就屬于依賴關系,不同于關聯關系,依賴不具有“擁有關系”,而是一種相識關系,只在某個特定的地方才有關系。
關聯:表示接口與接口或類與類之間的依賴關系,表現為“擁有關系”;具體代碼可以用實例變量來表示。
組合:屬于關聯的特殊情況,體現了部分整體的關系,是一種“強擁有關系”;整體與部分擁有相同的生命周期,是一種強關聯;
聚合:屬于關聯的特殊情況,也體現了部分整體的關系,是一種“弱擁有關系”;整體和部分可以有不一樣的生命周期。是一種弱關聯;
它們關系的強弱順序:泛化= 實現> 組合> 聚合> 關聯> 依賴?
spring IoC容器依賴有兩層含義:bean依賴容器和容器注入bean的依賴資源。
- bean依賴容器:這里的依賴是指容器負責創建bean,并管理bean的生命周期,正式由于容器來控制創建bean并注入依賴,也就是控制值被反轉了,這也正式IoC名字的由來,此處的依賴指的是bean和容器之間的依賴關系。
- 容器注入bean的依賴資源:依賴資源可以是bean、外部文件、常量數據等,在Java中都反應為對象,并且有容器負責組裝bean之間的依賴關系,此處的依賴指的是bean之間的關系可以認為是傳統類與類之間的關聯、組合、聚合關系。
2、為什么要依賴注入
- 動態替換bean依賴對象,程序更靈活:替換bean對象無需更改源文件,直接修改配置文件即可。
- 更好實踐面向接口編程,代碼更清晰:在bean中只需指定依賴對象的接口,接口定義依賴對象完成的功能,通過容器注入依賴實現。
- 更好實踐優先使用組合,而不是繼承:因為IoC容器采用注入依賴,也就是組合對象,從而更好的實現對象的組合。
- 增加bean的復用性:依賴于對象組合,bean可復用且復用更簡單
- 降低bean之間的耦合:由于我們完全面向接口編程,在代碼中沒有直接引用bean依賴實現,全部引用接口,而且不會顯示創建依賴對象代碼。
- 代碼結構更清晰:要應用依賴注入,代碼結構要按照規約方式進行書寫,從而更好的應用一些最佳實踐,因此代碼結構更清晰。
如何設計好類結構才是關鍵,依賴注入只是裝配對象的一種手段。上一篇我們已經了解了bean依賴容器,spring IoC容器注入依賴資源主要有以下三種形式:
構造器注入:就是容器實例化bean時注入那些依賴,通過在bean定義中指定構造器參數注入依賴,包括實例工廠方法參數注入依賴。
setter注入:通過setter方法注入依賴。
方法注入:通過配置方式替換掉bean方法,也就是通過配置改變bean方法功能。
3、依賴注入具體配置
3.1 構造器注入:
3.1.1?使用構造器注入通過配置構造器參數實現,構造器參數就是依賴。除了構造器方式還有實例工廠,靜態工廠可以進行構造器注入。
構造器注入可以根據參數的索引注入,參數的類型注入或參數名注入(參數名注入有限制:編譯程序時打開調試模式或在構造器上使用@ConstructorProperties注解指定參數名)
1 public class HelloImpl3 implements HelloApi { 2 private String message; 3 private int index; 4 //@java.beans.ConstructorProperties({"message", "index"}) 5 public HelloImpl3(String message, int index) { 6 this.message = message; 7 this.index = index; 8 } 9 @Override 10 public void sayHello() { 11 System.out.println(index + ":" + message); 12 } 1 <!-- 通過構造器參數索引方式依賴注入 --> 2 <bean id="byIndex" class="cn.javass.spring.chapter3.HelloImpl3"> 3 <constructor-arg index="0" value="Hello World!"/> 4 <constructor-arg index="1" value="1"/> 5 </bean> 6 <!-- 通過構造器參數類型方式依賴注入 --> 7 <bean id="byType" class="cn.javass.spring.chapter3.HelloImpl3"> 8 <constructor-arg type="java.lang.String" value="Hello World!"/> 9 <constructor-arg type="int" value="2"/> 10 </bean> 11 <!-- 通過構造器參數名稱方式依賴注入 --> 12 <bean id="byName" class="cn.javass.spring.chapter3.HelloImpl3"> 13 <constructor-arg name="message" value="Hello World!"/> 14 <constructor-arg name="index" value="3"/> 15 </bean> 1 @Test 2 public void testConstructorDependencyInjectTest() { 3 BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/constructorDependencyInject.xml"); 4 //獲取根據參數索引依賴注入的Bean 5 HelloApi byIndex = beanFactory.getBean("byIndex", HelloApi.class); 6 byIndex.sayHello(); 7 //獲取根據參數類型依賴注入的Bean 8 HelloApi byType = beanFactory.getBean("byType", HelloApi.class); 9 byType.sayHello(); 10 //獲取根據參數名字依賴注入的Bean 11 HelloApi byName = beanFactory.getBean("byName", HelloApi.class); 12 byName.sayHello(); 13 }? 3.1.2?靜態工廠方法注入和實例工廠方法注入
1 <!--靜態工廠方法--> 2 <bean id="byIndex" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance"> 3 <constructor-arg index="0" value="Hello World!"/> 4 <constructor-arg index="1" value="1"/> 5 </bean> 6 <bean id="byType" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance"> 7 <constructor-arg type="java.lang.String" value="Hello World!"/> 8 <constructor-arg type="int" value="2"/> 9 </bean> 10 <bean id="byName" class="cn.javass.spring.chapter3.DependencyInjectByStaticFactory" factory-method="newInstance"> 11 <constructor-arg name="message" value="Hello World!"/> 12 <constructor-arg name="index" value="3"/> 13 </bean> 24 <!--實例工廠方法--> 25 <bean id="instanceFactory" class="cn.javass.spring.chapter3.DependencyInjectByInstanceFactory"/> 26 <bean id="byIndex" factory-bean="instanceFactory" factory-method="newInstance"> 27 <constructor-arg index="0" value="Hello World!"/> 28 <constructor-arg index="1" value="1"/> 29 </bean> 30 <bean id="byType" factory-bean="instanceFactory" factory-method="newInstance"> 31 <constructor-arg type="java.lang.String" value="Hello World!"/> 32 <constructor-arg type="int" value="2"/> 33 </bean> 34 <bean id="byName" factory-bean="instanceFactory" factory-method="newInstance"> 35 <constructor-arg name="message" value="Hello World!"/> 36 <constructor-arg name="index" value="3"/> 37 </bean> 1 //靜態工廠類 2 package cn.javass.spring.chapter3; 3 import cn.javass.spring.chapter2.helloworld.HelloApi; 4 public class DependencyInjectByStaticFactory { 5 public static HelloApi newInstance(String message, int index) { 6 return new HelloImpl3(message, index); 7 } 8 } 9 //實例工廠類 10 package cn.javass.spring.chapter3; 11 import cn.javass.spring.chapter2.helloworld.HelloApi; 12 public class DependencyInjectByInstanceFactory { 13 public HelloApi newInstance(String message, int index) { 14 return new HelloImpl3(message, index); 15 } 16 }? 因為參數名需做額外配置,因此不建議使用根據參數名進行構造器注入
3.2 setter注入
setter注入,是通過構造器、靜態工廠、實例工廠實例化好bean中,再調用bean類的setter方法注入依賴。
1 <!-- 通過setter方式進行依賴注入 --> 2 <bean id="bean" class="cn.javass.spring.chapter3.HelloImpl4"> 3 <property name="message" value="Hello World!"/> 4 <property name="index"> 5 <value>1</value> 6 </property> 7 </bean> 1 package cn.javass.spring.chapter3; 2 import cn.javass.spring.chapter2.helloworld.HelloApi; 3 public class HelloImpl4 implements HelloApi { 4 private String message; 5 private int index; 6 //setter方法 7 public void setMessage(String message) { 8 this.message = message; 9 } 10 public void setIndex(int index) { 11 this.index = index; 12 } 13 @Override 14 public void sayHello() { 15 System.out.println(index + ":" + message); 16 } 17 } 18 19 @Test 20 public void testSetterDependencyInject() { 21 BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/setterDependencyInject.xml"); 22 HelloApi bean = beanFactory.getBean("bean", HelloApi.class); 23 bean.sayHello(); 24 }
JavaBean本質就是一個pojo,具體有如下限制:
該類必須有公共的無慘構造器
屬性為private訪問級別
屬性必要時通過一組setter和getter方法來訪問
3.3 常量注入
注入常量是依賴注入中最簡單的,配置方式如下:
1 <property name="message" value="Hello World!"/> 2 或 3 <property name="index"><value>1</value></property>以上兩種方式都可以,從配置來看第一種更簡潔,此處的value中指定的全是字符串,由spring容器將此字符串轉換成屬性所需的類型,如果轉換出錯則拋出相應的異常。spring容器目前能對各種基本類型把配置的字符串參數轉換為所需的類型。
1 //測試類 2 public class BooleanTestBean { 3 private boolean success; 4 public void setSuccess(boolean success) { 5 this.success = success; 6 } 7 public boolean isSuccess() { 8 return success; 9 } 10 } 1 <!-- boolean參數值可以用on/off --> 2 <bean id="bean2" class="cn.javass.spring.chapter3.bean.BooleanTestBean"> 3 <property name="success" value="on"/> 4 </bean> 5 <!-- boolean參數值可以用yes/no --> 6 <bean id="bean3" class="cn.javass.spring.chapter3.bean.BooleanTestBean"> 7 <property name="success" value="yes"/> 8 </bean> 9 <!-- boolean參數值可以用1/0 --> 10 <bean id="bean4" class="cn.javass.spring.chapter3.bean.BooleanTestBean"> 11 <property name="success" value="1"/> 12 </bean>3.4 注入集合、數組和字典
spring IoC容器不僅能注入簡單的數據類型,還能注入集合(Collection、Set、List)類型、數組類型、字典數據類型、Properties類型。
3.4.1?注入集合類型:
- List類型:需要使用list標簽注入,其具體配置如下:
1 <bean id="listBean" class="cn.javass.spring.chapter3.bean.ListTestBean"> 2 <property name="values"> 3 <list> 4 <value>1</value> 5 <value>2</value> 6 <value>3</value> 7 </list> 8 </property> 9 </bean> 1 package cn.javass.spring.chapter3.bean; 2 import java.util.List; 3 public class ListTestBean { 4 private List<String> values; 5 public List<String> getValues() { 6 return values; 7 } 8 public void setValues(List<String> values) { 9 this.values = values; 10 } 11 } 12 @Test 13 public void testListInject() { 14 BeanFactory beanFactory = new ClassPathXmlApplicationContext("chapter3/listInject.xml"); 15 ListTestBean listBean = beanFactory.getBean("listBean", ListTestBean.class); 16 System.out.println(listBean.getValues().size()); 17 Assert.assertEquals(3, listBean.getValues().size()); 18 }
- set類型:需要使用set標簽來配置注入,其配置參數含義與list相同
- Collection類型:由于Collection類型是List和Set類型的基類型,所以使用list和set標簽都可以進行注入,配置方式和以上配置方式相同。
3.4.2 注入數組類型
需要使用array標簽來配置注入,其中標簽屬性“value-type”和“merge”與list標簽含義完全相同。具體配置如下:
3.4.3 注入字典類型:
字典類型是包含鍵值對數據的數據結構,需要使用map、entry標簽來配置注入,其屬性key-type和value-type分別指定鍵值數據類型,其含義同list標簽相同。使用key、value字標簽分別指定鍵值數據。具體配置如下:
3.4.4 Properties注入:
spring能注入java.util.Properties類型數據,需要使用props標簽來配置注入,鍵值類型必須是String,不能變。字標簽<prop key=“鍵”>值<prop>來指定鍵值對,具體配置如下:
?
?
?
轉載于:https://www.cnblogs.com/ouhouki/p/9692701.html
總結
以上是生活随笔為你收集整理的srping基础——DI(三)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux - alias 定义的变量
- 下一篇: 为什么我认为现阶段HIDS处于攻防不对等