1. 程式人生 > >Spring IOC介紹與4種注入方式

Spring IOC介紹與4種注入方式

Spring IOC介紹

 

spring的核心思想是IOC和AOP,IOC-控制反轉,是一個重要的面向物件程式設計的法則來消減計算機程式的耦合問題,控制反轉一般分為兩種型別,依賴注入和依賴查詢,依賴什麼?為什麼需要依賴?注入什麼?控制什麼?依賴注入和控制反轉是一樣的概念嗎?接觸新的知識,小編的腦袋中全是大大的問號,不過沒有關係,今天這篇博文,小編主要來簡單的介紹一下在spring 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類中。
第五個問題:控制反轉和依賴注入式同一個概念嗎? 依賴注入和控制反轉是對同一件事情的不同描述,從某個方面講,就是它們描述的角度不同。依賴注入是從應用程式的角度在描述,可以把依賴注入描述完整點:應用程式依賴容器建立並注入它所需要的外部資源;而控制反轉是從容器的角度在描述,描述完整點:容器控制應用程式,由容器反向的嚮應用程式注入應用程式所需要的外部資源。


4種注入方式

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

a.介面注入

b.setter方法注入

c.構造方法注入

d.註解方式注入
接著小編對這三種注入方式一一進行講解,通過demo的講解,希望能夠幫助小夥伴們更好的理解,不足之處還請多多指教。


介面注入

public class ClassA {  
  private InterfaceB clzB; public void doSomething() { Ojbect obj = Class.forName(Config.BImplementation).newInstance(); clzB = (InterfaceB)obj; clzB.doIt(); } …… 

解釋一下上述的程式碼部分,ClassA依賴於InterfaceB的實現,我們如何獲得InterfaceB的實現例項呢?傳統的方法是在程式碼中建立 InterfaceB實現類的例項,並將賦予clzB.這樣一來,ClassA在編譯期即依賴於InterfaceB的實現。為了將呼叫者與實現者在編譯期分離,於是有了上面的程式碼。我們根據預先在配置檔案中設定的實現類的類名(Config.BImplementation),動態載入實現類,並通過InterfaceB強制轉型後為ClassA所用,這就是介面注入的一個最原始的雛形。


setter方法注入

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

<?xml version="1.0" encoding="UTF-8"?>    
<beans xmlns="http://www.springframework.org/schema/beans"    
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 使用spring管理物件的建立,還有物件的依賴關係 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自動建立相應的UserDao實現,都是由容器管理--> <!-- (2)在UserManager中提供建構函式,讓spring將UserDao實現注入(DI)過來 --> <!-- (3)讓spring管理我們物件的建立和依賴關係,必須將依賴關係配置到spring的核心配置檔案中 --> <property name="userDao" ref="userDao4Oracle"></property> </bean> 

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

import com.tgb.spring.dao.UserDao;    
    
public class UserManagerImpl implements UserManager{ private UserDao userDao; //使用設值方式賦值 public void setUserDao(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); } } 

構造器注入

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

<?xml version="1.0" encoding="UTF-8"?>    
    <beans xmlns="http://www.springframework.org/schema/beans"    
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd  http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.1.xsd  http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.1.xsd"> <!-- 使用spring管理物件的建立,還有物件的依賴關係 --> <bean id="userDao4Mysql" class="com.tgb.spring.dao.UserDao4MysqlImpl"/> <bean id="userDao4Oracle" class="com.tgb.spring.dao.UserDao4OracleImpl"/> <bean id="userManager" class="com.tgb.spring.manager.UserManagerImpl"> <!-- (1)userManager使用了userDao,Ioc是自動建立相應的UserDao實現,都是由容器管理--> <!-- (2)在UserManager中提供建構函式,讓spring將UserDao實現注入(DI)過來 --> <!-- (3)讓spring管理我們物件的建立和依賴關係,必須將依賴關係配置到spring的核心配置檔案中 --> <constructor-arg ref="userDao4Oracle"/> </bean> </beans> 

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

import com.tgb.spring.dao.UserDao;    
    
    public class UserManagerImpl implements UserManager{ private UserDao userDao; //使用構造方式賦值 public UserManagerImpl(UserDao userDao) { this.userDao = userDao; } @Override public void addUser(String userName, String password) { userDao.addUser(userName, password); } } 

使用欄位(Filed)注入(用註解方式)

在Spring中,注入依賴物件可以採用手工裝配或自動裝配,在實際應用開發中建議使用手工裝配,因為自動裝配會產生許多未知情況,開發人員無法預見最終的裝配結果。

手工裝配依賴物件又分為兩種方式:

一種是在XML檔案中,通過在bean節點下配置;如上面講到的使用屬性的setter方法注入依賴物件和使用構造器方法注入依賴物件都是這種方式。

另一種就是在java程式碼中使用註解的方式進行裝配,在程式碼中加入@Resource或者@Autowired、

 

  • Autowired是自動注入,自動從spring的上下文找到合適的bean來注入
  • Resource用來指定名稱注入
  • Qualifier和Autowired配合使用,指定bean的名稱,如
@Autowired  
@Qualifier("userDAO")  
private UserDAO userDAO;  

怎樣使用註解的方式來為某個bena注入依賴物件呢?

首先,我們需要在Spring容器的配置檔案applicationContext.Xml檔案中配置以下資訊,該信心是一個Spring配置檔案的模板:

<?xml version="1.0" encoding="UTF-8"?>  
  
<beans  
  
xmlns="http://www.springframework.org/schema/beans"  
  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-2.5.xsd  "> </beans> 

注意:只有配置了紅色部分的程式碼才可以引入註解的名稱空間,否則報錯。

以上的配置隱式的註冊了多個對註釋進行解析的處理器:AutowiredAnnotationBeanPostProcessor、

CommonAnnotationBeanPostProcessor、

PersistenceAnnotationBeanPostProcessor等。

其次,在配置檔案中開啟<context:annotation-config>節點,告訴Spring容器可以用註解的方式注入依賴物件;其在配置檔案中的程式碼如下:

<beans>  
  
……  
  
<context:annotation-config></context:annotation-config>  
  
……  
  
</beans>  

第三,在配置檔案中配置bean物件,如下:

<bean id="userDao" class="com.springtest.dao.impl.UserDAOImpl"></bean> <bean id="userBiz" class="com.springtest.biz.impl.UserBizImpl"></bean> 

第四,在需要依賴注入的BIZ類中,宣告一個依賴物件,不用生成該依賴物件的setter方法,並且為該物件添加註解:

public class UserBizImpl implements UserBiz { @Resource(name="userDao") private UserDAO userDao = null; public void addUser() { this.userDao.addUser(); } } 

其中,在Java程式碼中可以使用@Autowired或@Resource註解方式進行Spring的依賴注入。兩者的區別是:@Autowired預設按型別裝配,@Resource預設按名稱裝配,當找不到與名稱匹配的bean時,才會按型別裝配。

比如:我們用@Autowired為上面的程式碼UserDAO介面的例項物件進行註解,它會到Spring容器中去尋找與UserDAO物件相匹配的型別,如果找到該型別則將該型別注入到userdao欄位中;

如果用@Resource進行依賴注入,它先會根據指定的name屬性去Spring容器中尋找與該名稱匹配的型別,例如:@Resource(name="userDao"),如果沒有找到該名稱,則會按照型別去尋找,找到之後,會對欄位userDao進行注入。

通常我們使用@Resource。

使用註解注入依賴物件不用再在程式碼中寫依賴物件的setter方法或者該類的構造方法,並且不用再配置檔案中配置大量的依賴物件,使程式碼更加簡潔,清晰,易於維護。

在Spring IOC程式設計的實際開發中推薦使用註解的方式進行依賴注入。

依賴注入—自動裝配:略(不推薦)


總結:

介面注入:

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

Setter 注入:

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

構造器注入:

在構造期間完成一個完整的、合法的物件。所有依賴關係在建構函式中集中呈現。依賴關係在構造時由容器一次性設定,元件被建立之後一直處於相對“不變”的穩定狀態。只有元件的建立者關心其內部依賴關係,對呼叫者而言,該依賴關係處於“黑盒”之中。

註解注入:

使用註解注入依賴物件不用再在程式碼中寫依賴物件的setter方法或者該類的構造方法,並且不用再配置檔案中配置大量的依賴物件,使程式碼更加簡潔,清晰,易於維護。

在Spring IOC程式設計的實際開發中推薦使用註解的方式進行依賴注入。