測試同學(xué)上手Spring 之DI深入解析
前面已經(jīng)介紹了如何上手Spirng編碼以及IOC的核心概念,今天給大家講解Spring的另一個重點——DI。
Spring核心模塊
DI概念
IoC 其實有兩種方式,一種就是 DI(Dependency Injection) ,而另一種是 DL(Dependency Lookup)即依賴查找。前者是當前組件被動接受IoC容器注入的依賴組件,而后者則是組件主動去某個服務(wù)注冊地查找其依賴的組件,我們這里重點介紹DI。
IoC的一個重點是在系統(tǒng)運行中,動態(tài)的向某個對象提供它所需要的其他對象。這一點是通過DI來實現(xiàn)的。比如對象A需要操作數(shù)據(jù)庫,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有了spring我們就只需要告訴spring,A中需要一個Connection,至于這個Connection怎么構(gòu)造,何時構(gòu)造,A不需要知道。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何代碼就可指定目標需要的資源,完成自身的業(yè)務(wù)邏輯,而不需要關(guān)心具體的資源來自何處,由誰實現(xiàn)。在系統(tǒng)運行時,spring會在適當?shù)臅r候制造一個Connection,然后像打針一樣,注射到A當中,這樣就完成了對各個對象之間關(guān)系的控制。A需要依賴Connection才能正常運行,而這個Connection是由spring注入到A中的,依賴注入的名字就這么來的。Spring是通過反射技術(shù)實現(xiàn)注入的,它允許程序在運行的時候動態(tài)的生成對象、執(zhí)行對象的方法、改變對象的屬性。
簡單的總結(jié)一下依賴注入:
- 依賴 : 指Bean對象的創(chuàng)建依賴于容器 。
 - 注入 : 指Bean對象所依賴的資源 , 由容器來設(shè)置和裝配。
 
注入的方式主要包括Setter注入(重點)、構(gòu)造器注入和參數(shù)直接注入。還有拓展方式注入,即:p命名空間注入和c命名空間注入,這里就不再展開介紹了,有興趣的同學(xué)可以自行研究。
Setter注入
IoC 容器使用 setter 方法注入被依賴的實例。通過調(diào)用無參構(gòu)造器或無參 static 工廠方法實例化 bean 后,調(diào)用該 bean的setter 方法(類中必須有屬性的set方法),即可實現(xiàn)基于setter的DI
代碼如下:
- public class Address {
 - private String address;
 - public String getAddress() {
 - return address;
 - }
 - public void setAddress(String address) {
 - this.address = address;
 - }
 - }
 
- import java.util.List;
 - import java.util.Map;
 - import java.util.Properties;
 - import java.util.Set;
 - public class Student {
 - private String name;
 - private Address address;
 - private String[] books;
 - private List<String> hobbys;
 - private Map<String,String> card;
 - private Set<String> games;
 - private String wife;
 - private Properties info;
 - public void setName(String name) {
 - this.name = name;
 - }
 - public String getName() {
 - return this.name;
 - }
 - public void setAddress(Address address) {
 - this.address = address;
 - }
 - public void setBooks(String[] books) {
 - this.books = books;
 - }
 - public void setHobbys(List<String> hobbys) {
 - this.hobbys = hobbys;
 - }
 - public void setCard(Map<String, String> card) {
 - this.card = card;
 - }
 - public void setGames(Set<String> games) {
 - this.games = games;
 - }
 - public void setWife(String wife) {
 - this.wife = wife;
 - }
 - public void setInfo(Properties info) {
 - this.info = info;
 - }
 - public void show(){
 - System.out.println("name="+ name
 - +",address="+ address.getAddress()
 - +",books="
 - );
 - for (String book:books){
 - System.out.print("<<"+book+">>\t");
 - }
 - System.out.println("\nhobbys:"+hobbys);
 - System.out.println("card:"+card);
 - System.out.println("games:"+games);
 - System.out.println("wife:"+wife);
 - System.out.println("info:"+info);
 - }
 - }
 
配置文件
- <bean id="student" class="com.my.demo.Student">
 - <property name="name" value="小明"/>
 - </bean>
 
配置文件中把name 賦值為小明,即完成了對代碼 private String name的注入。
測試類
- public static void main(String[] args) {
 - ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
 - Student student=(Student)context.getBean("student");
 - System.out.println(student.getName());
 - }
 
運行結(jié)果,輸出:小明
常見注入方式的xml 配置如下:
bean注入
使用ref進行引入其他bean
- <bean id="student" class="com.my.demo.Student">
 - <property name="name" value="小明"/>
 - <property name="address" ref="addr"/>
 - </bean>
 
數(shù)組注入
- <property name="books">
 - <array>
 - <value>數(shù)學(xué)</value>
 - <value>語文</value>
 - <value>英語</value>
 - </array>
 - </property>
 
List注入
- <property name="hobbys">
 - <list>
 - <value>聽歌</value>
 - <value>看電影</value>
 - <value>打游戲</value>
 - </list>
 - </property>
 
Map注入
- <property name="card">
 - <map>
 - <entry key="招行" value="123456789"/>
 - <entry key="工行" value="987654321"/>
 - </map>
 - </property>
 
set注入
- <property name="games">
 - <set>
 - <value>CS</value>
 - <value>斗地主</value>
 - <value>消消樂</value>
 - </set>
 - </property>
 
Null注入
- <property name="wife"><null/></property>
 
Properties注入
- <propertyname="info">
 - <props>
 - <propkey="學(xué)號">123456</prop>
 - <propkey="性別">男</prop>
 - <propkey="姓名">小明</prop>
 - </props>
 - </property>
 
測試方法
- public static void main(String[] args) {
 - ApplicationContextcontext = new ClassPathXmlApplicationContext("bean1.xml");
 - Studentstudent=(Student)context.getBean("student");
 - student.show();
 - }
 
運行結(jié)果,輸出:
name=小明,address=北京,books=
<<數(shù)學(xué)>> <<語文>> <<英語>>
hobbys:[聽歌, 看電影, 打游戲]
card:{招行=123456789, 工行=987654321}
games:[CS, 斗地主, 消消樂]
wife:null
info:{學(xué)號=123456, 性別=男, 姓名=小明}
構(gòu)造器注入
指IoC 容器使用構(gòu)造方法注入被依賴的實例?;跇?gòu)造器的 DI 通過調(diào)用帶參數(shù)的構(gòu)造方法實現(xiàn),每個參數(shù)代表一個依賴。
代碼如下:
- public class Student2{
 - private String name;
 - public Student2(String name) {
 - this.name = name;
 - }
 - public void setName(String name) {
 - this.name = name;
 - }
 - public void show(){
 - System.out.println("name="+ name );
 - }
 - }
 
配置文件中設(shè)置
- <!-- 第一種根據(jù)index參數(shù)下標設(shè)置 -->
 - <bean id="student1" class="com.my.demo.Student2">
 - <!-- index是構(gòu)造方法 , 下標從0開始 -->
 - <constructor-arg index="0" value="kevin1"/>
 - </bean>
 - <!--第二種根據(jù)參數(shù)名字設(shè)置 -->
 - <bean id="student2" class="com.my.demo.Student2">
 - <!-- name指參數(shù)名 -->
 - <constructor-arg name="name" value="kevin2"/>
 - </bean>
 - <!--第三種根據(jù)參數(shù)類型設(shè)置(不推薦使用) -->
 - <bean id="student3" class="com.my.demo.Student2">
 - <constructor-arg type="java.lang.String" value="kevin3"/>
 - </bean>
 
測試代碼
- public static void main(String[] args) {
 - ApplicationContextcontext = new ClassPathXmlApplicationContext("bean3.xml");
 - Student2 user = (Student2) context.getBean("student1")
 - user.show();
 - }
 
運行結(jié)果:
name=kevin1
參數(shù)直接注入
主要通過注解@Autowired、@Qualifier和@Resource來實現(xiàn)
@Autowired
@Autowired是按類型自動轉(zhuǎn)配的,不支持id匹配。
需要導(dǎo)入 spring-aop的包
配置文件中設(shè)置<
context:annotation-config/>
代碼:
- public class Animal {
 - @Autowired private Cat cat; //運行時spring通過DI會把Cat類實例化
 - @Autowired private Dog dog;//運行時spring通過DI會把Dog類實例化
 - public void printCatshot() {
 - cat.shout();
 - }
 - public void printDogshot() {
 - dog.shout();
 - }
 - }
 
@Qualifier
@Autowired是根據(jù)類型進行自動裝配的。如果當Spring上下文中存在一個類型的不同bean時,就會拋出BeanCreationException異常;我們可以使用@Qualifier配合@Autowired來解決這些問題。
代碼:
- @Autowired
 - @Qualifier(value= "dog1")
 - private Dog dog1;
 - beans.xml
 - <bean id="dog1" class="com.my.demo.Dog"/>
 - <bean id="dog2" class=" com.my.demo.Dog"/>
 
@Resource
@Resource是J2EE提供的, 需導(dǎo)入Package: javax.annotation.Resource;
@Resource如有指定的name屬性,先按該屬性進行byName方式查找裝配,其次再進行默認的byName方式進行裝配,都不成功,則報異常。
代碼
- @Resource(name = "dog2")
 - private Dog dog;
 - beans.xml
 - <bean id="dog1" class=" com.my.demo.Dog "/>
 - <bean id="dog2" class="com.my.demo.Dog "/>
 
最簡單的解釋
IoC通過DI技術(shù)主要實現(xiàn)了以下兩點:
- 在系統(tǒng)運行中,動態(tài)地向某個對象提供它所需要的其他對象;
 - 在系統(tǒng)運行中,動態(tài)地從配置文件中讀取數(shù)據(jù)來為對象的屬性進行賦值。
 
【編輯推薦】
















 
 
 









 
 
 
 