天天看點

spring IOC中三種依賴注入方式

Spring的核心思想是IOC和AOP,IOC-控制反轉,是一個重要的面向對象程式設計的法則,用來消減計算機程式之間的耦合問題,控制反轉一般分為兩種類型,依賴注入和依賴查找,依賴什麼?為什麼需要依賴?注入什麼?什麼時候注入,控制什麼?依賴注入和控制反轉是一樣的概念嗎?

依賴注入和控制反轉,目的是為了使類與類之間解耦合,提高系統的可擴充性和可維護性。我們可以從以下幾個方面了解:

a、參與者都有誰?

b、依賴:誰依賴誰?為什麼需要依賴?

c、注入:誰注入誰?什麼時候注入,又注入了什麼呢?

d、控制反轉:誰控制誰?控制什麼?為什麼叫反轉呢?存在正轉嗎?

e、控制反轉和依賴注入是同一個概念嗎?我們需要弄明白上面的問題,這樣對于控制反轉和依賴注入的了解有大大的幫助。

首先:第一個問題,參與者都有誰?

1)對象

2)IOC/DI容器

3)某個對象的外部資源

第二問題:依賴,誰依賴誰?為什麼需要依賴?

依賴嘛,很好了解的,對象依賴于IOC/DI容器,至于為什麼要依賴呢?對象需要IOC/DI容器來提供對象需要的外部資源(被依賴的對象)。

第三個問題:注入,誰注入誰?又注入了什麼呢?

顯而易見是IOC/DI容器注入對象,注入了what呢?肯定注入的是某個需要的東西那就是注入對象所需要的資源,肯定不會注入無關緊要的内容,你說呢?

第四個問題:控制反轉,誰控制誰?控制什麼?為什麼叫反轉呢?存在正轉嗎?

控制反轉,控制什麼?肯定是IOC/DI容器控制對象,主要是控制對象執行個體的建立,反轉是相對于正向而言的,那麼什麼算是正向的呢?考慮一下正常情況下的應用程式,如果要在A裡面使用C,你會怎麼做呢?當然是直接去建立C的對象,也就是說,是在A類中主動去擷取所需要的外部資源C,這種情況被稱為正向的。那麼什麼是反向呢?就是A類不再主動去擷取C,而是被動等待,等待IoC/DI的容器擷取一個C的執行個體,然後反向的注入到A類中。

第五個問題:控制反轉和依賴注入式同一個概念嗎?

依賴注入和控制反轉是對同一件事情的不同描述,從某個方面講,就是它們描述的角度不同。依賴注入是從應用程式的角度在描述,可以把依賴注入描述完整點:應用程式依賴容器建立并注入它所需要的外部資源;而控制反轉是從容器的角度在描述,描述完整點:容器控制應用程式,由容器反向的向應用程式注入應用程式所需要的外部資源。

了解了這些基本的概念,弄明白她們之間的聯系和差別,能夠幫助我們更好的了解,接着小編來重點介紹一下依賴注入,在spring ioc中有三種依賴注入,分别是:

a、接口注入;

b、setter方法注入;

c、構造方法注入;

接着小編對這三種注入方式一一進行講解

接口注入

  1. public class ClassA {  
  2.   private InterfaceB clzB;  
  3.   public void doSomething() {  
  4.     Ojbect obj = Class.forName(Config.BImplementation).newInstance();  
  5.     clzB = (InterfaceB)obj;  
  6.     clzB.doIt();   
  7.   }  
  8. ……  
  9. }  

解釋一下上述的代碼部分,ClassA依賴于InterfaceB的實作,我們如何獲得InterfaceB的實作執行個體呢?傳統的方法是在代碼中建立 InterfaceB實作類的執行個體,并将賦予clzB.這樣一來,ClassA在編譯期即依賴于InterfaceB的實作。為了将調用者與實作者在編譯期分離,于是有了上面的代碼。我們根據預先在配置檔案中設定的實作類的類名(Config.BImplementation),動态加載實作類,并通過InterfaceB強制轉型後為ClassA所用,這就是接口注入的一個最原始的雛形。

setter方法注入

setter注入模式在實際開發中有非常廣泛的應用,setter方法更加直覺,我們來看一下spring的配置檔案:

  1. <?xml version="1.0" encoding="UTF-8"?>    
  2. <beans xmlns="http://www.springframework.org/schema/beans"    
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  4.          xmlns:aop="http://www.springframework.org/schema/aop"    
  5.          xmlns:tx="http://www.springframework.org/schema/tx"    
  6.          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd    
  7.            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd    
  8.            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">    
  9.     <!-- 使用spring管理對象的建立,還有對象的依賴關系 -->    
  10.     <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/>    
  11.     <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/>    
  12.     <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl">    
  13.         <!-- (1)userManager使用了userDao,Ioc是自動建立相應的UserDao實作,都是由容器管理-->    
  14.         <!-- (2)在UserManager中提供構造函數,讓spring将UserDao實作注入(DI)過來 -->    
  15.         <!-- (3)讓spring管理我們對象的建立和依賴關系,必須将依賴關系配置到spring的核心配置檔案中 -->    
  16.         <property name="userDao" ref="userDao4Oracle"></property>    
  17.     </bean>     
  18. </beans>  

接着我們來看一下,setter表示依賴關系的寫法

  1. import com.tgb.spring.dao.UserDao;    
  2. public class UserManagerImpl implements UserManager{    
  3.     private UserDao userDao;    
  4.     //使用設值方式指派    
  5.     public void setUserDao(UserDao userDao) {    
  6.         this.userDao = userDao;    
  7.     }    
  8.     @Override    
  9.     public void addUser(String userName, String password) {    
  10.         userDao.addUser(userName, password);    
  11. }    

構造器注入

構造器注入,即通過構造函數完成依賴關系的設定。我們看一下spring的配置檔案:

  1.     <beans xmlns="http://www.springframework.org/schema/beans"    
  2.              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    
  3.              xmlns:aop="http://www.springframework.org/schema/aop"    
  4.              xmlns:tx="http://www.springframework.org/schema/tx"    
  5.              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd    
  6.                http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd    
  7.                http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd">    
  8.         <!-- 使用spring管理對象的建立,還有對象的依賴關系 -->    
  9.         <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/>    
  10.         <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/>    
  11.         <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl">    
  12.             <!-- (1)userManager使用了userDao,Ioc是自動建立相應的UserDao實作,都是由容器管理-->    
  13.             <!-- (2)在UserManager中提供構造函數,讓spring将UserDao實作注入(DI)過來 -->    
  14.             <!-- (3)讓spring管理我們對象的建立和依賴關系,必須将依賴關系配置到spring的核心配置檔案中 -->    
  15.             <constructor-arg ref="userDao4Oracle"/>    
  16.         </bean>    
  17.     </beans>    

我們再來看一下,構造器表示依賴關系的寫法,代碼如下所示:

  1.     public class UserManagerImpl implements UserManager{    
  2.         private UserDao userDao;    
  3.         //使用構造方式指派    
  4.         public UserManagerImpl(UserDao userDao) {    
  5.             this.userDao = userDao;    
  6.         }    
  7.         @Override    
  8.         public void addUser(String userName, String password) {    
  9.             userDao.addUser(userName, password);    
  10.     }    

接口注入 && setter注入 && 構造器注入三種注入方式的比較

 接口注入:

接口注入模式因為具備侵入性,它要求元件必須與特定的接口相關聯,是以并不被看好,實際使用有限。

Setter 注入:

對于習慣了傳統 javabean 開發的程式員,通過 setter 方法設定依賴關系更加直覺。如果依賴關系較為複雜,那麼構造子注入模式的構造函數也會相當龐大,而此時設值注入模式則更為簡潔。如果用到了第三方類庫,可能要求我們的元件提供一個預設的構造函數,此時構造子注入模式也不适用。

構造器注入:

在構造期間完成一個完整的、合法的對象。所有依賴關系在構造函數中集中呈現。依賴關系在構造時由容器一次性設定,元件被建立之後一直處于相對“不變”的穩定狀态。隻有元件的建立者關心其内部依賴關系,對調用者而言,該依賴關系處于“黑盒”之中。