SpringMVC 乾貨系列:從零搭建 SpringMVC+mybatis(三):Spring 兩大核心之 IOC/DI 學習 | 掘金技術徵文

嘟嘟MD發表於2017-04-26

原本地址:SpringMVC乾貨系列:從零搭建SpringMVC+mybatis(三):Spring兩大核心之IOC/DI學習
部落格地址:tengj.top/

前言

上篇講了SpringMVC的實現原理以及常用的註解,其實裡面都用到的spring的核心概念,那就是IOC/DI,今天給大家介紹下這核心概念IOC/DI。

正文

分享Iteye的開濤這位技術牛人對Spring框架的IOC的理解,寫得非常通俗易懂。

IoC是什麼

Ioc—Inversion of Control,即“控制反轉”,不是什麼技術,而是一種設計思想。在Java開發中,Ioc意味著將你設計好的物件交給容器控制,而不是傳統的在你的物件內部直接控制。如何理解好Ioc呢?理解好Ioc的關鍵是要明確“誰控制誰,控制什麼,為何是反轉(有反轉就應該有正轉了),哪些方面反轉了”,那我們來深入分析一下:

  • 誰控制誰,控制什麼:傳統Java SE程式設計,我們直接在物件內部通過new進行建立物件,是程式主動去建立依賴物件;而IoC是有專門一個容器來建立這些物件,即由Ioc容器來控制對 象的建立;誰控制誰?當然是IoC 容器控制了物件;控制什麼?那就是主要控制了外部資源獲取(不只是物件包括比如檔案等)。

  • 為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程式是由我們自己在物件中主動控制去直接獲取依賴物件,也就是正轉;而反轉則是由容器來幫忙建立及注入依賴物件;為何是反轉?因為由容器幫我們查詢及注入依賴物件,物件只是被動的接受依賴物件,所以是反轉;哪些方面反轉了?依賴物件的獲取被反轉了。

用圖例說明一下,傳統程式設計如圖2-1,都是主動去建立相關物件然後再組合起來:

SpringMVC 乾貨系列:從零搭建 SpringMVC+mybatis(三):Spring 兩大核心之 IOC/DI 學習 | 掘金技術徵文

當有了IoC/DI的容器後,在客戶端類中不再主動去建立這些物件了,如圖所示:

SpringMVC 乾貨系列:從零搭建 SpringMVC+mybatis(三):Spring 兩大核心之 IOC/DI 學習 | 掘金技術徵文

IoC能做什麼

IoC 不是一種技術,只是一種思想,一個重要的物件導向程式設計的法則,它能指導我們如何設計出鬆耦合、更優良的程式。傳統應用程式都是由我們在類內部主動建立依賴物件,從而導致類與類之間高耦合,難於測試;有了IoC容器後,把建立和查詢依賴物件的控制權交給了容器,由容器進行注入組合物件,所以物件與物件之間是 鬆散耦合,這樣也方便測試,利於功能複用,更重要的是使得程式的整個體系結構變得非常靈活。

其實IoC對程式設計帶來的最大改變不是從程式碼上,而是從思想上,發生了“主從換位”的變化。應用程式原本是老大,要獲取什麼資源都是主動出擊,但是在IoC/DI思想中,應用程式就變成被動的了,被動的等待IoC容器來建立並注入它所需要的資源了。

IoC很好的體現了物件導向設計法則之一—— 好萊塢法則:“別找我們,我們找你”;即由IoC容器幫物件找相應的依賴物件並注入,而不是由物件主動去找。

IoC和DI

DI—Dependency Injection,即“依賴注入”:元件之間依賴關係由容器在執行期決定,形象的說,即由容器動態的將某個依賴關係注入到元件之中。依賴注入的目的並非為軟體系統帶來更多功能,而是為了提升元件重用的頻率,併為系統搭建一個靈活、可擴充套件的平臺。通過依賴注入機制,我們只需要通過簡單的配置,而無需任何程式碼就可指定目標需要的資源,完成自身的業務邏輯,而不需要關心具體的資源來自何處,由誰實現。

理解DI的關鍵是:“誰依賴誰,為什麼需要依賴,誰注入誰,注入了什麼”,那我們來深入分析一下:

  • 誰依賴於誰:當然是應用程式依賴於IoC容器;

  • 為什麼需要依賴:應用程式需要IoC容器來提供物件需要的外部資源;

  • 誰注入誰:很明顯是IoC容器注入應用程式某個物件,應用程式依賴的物件;

  • 注入了什麼:就是注入某個物件所需要的外部資源(包括物件、資源、常量資料)。

IoC和DI由什麼關係呢?其實它們是同一個概念的不同角度描述,由於控制反轉概念比較含糊(可能只是理解為容器控制物件這一個層面,很難讓人想到誰來維護物件關係),所以2004年大師級人物Martin Fowler又給出了一個新的名字:“依賴注入”,相對IoC 而言,“依賴注入”明確描述了“被注入物件依賴IoC容器配置依賴物件”。

看過很多對Spring的Ioc理解的文章,好多人對Ioc和DI的解釋都晦澀難懂,反正就是一種說不清,道不明的感覺,讀完之後依然是一頭霧水,感覺就是開濤這位技術牛人寫得特別通俗易懂,他清楚地解釋了IoC(控制反轉) 和DI(依賴注入)中的每一個字,讀完之後給人一種豁然開朗的感覺。我相信對於初學Spring框架的人對Ioc的理解應該是有很大幫助的。

Spring配置的可選方案

上面介紹了IOC跟DI的概念,接著,我將歸納一下使用Spring裝備bean的基礎知識,因為DI是Spring的最基本要素。所以在開發的基於Spring的應用時,我們隨時都在使用這些技術。
當描述bean如何進行裝配時,Spring具有非常大的靈活性,它提供了三種主要的裝配機制:

  • 在XML中進行顯示配置
  • 在Java中進行顯示配置
  • 隱式的bean發現機制和自動裝配

雖然看上去提供三種可選的配置方案會使Spring變得複雜。其實,你可以根據實際專案選擇,對了,上面這三種其實可以混合搭配,目前博主使用的就是自動裝配(也就是註解)+XML混合使用。這也是目前比較流行的方式。

下面將主要介紹自動化裝備Bean+XML的混合搭配

自動化裝配bean

當前來說,相比較前面兩種顯示配置,從便利性方面來看,最強大的還是Spring的自動化配置。
Spring從兩個角度來實現自動化裝配:

  • 元件掃描(component scanning):Spring會自動發現應用上下文中所建立的bean
  • 自動裝配(autowiring):Spring自動滿足bean之間的依賴

元件掃描和自動裝配組合在一起就能發揮出強大的威力,他們能夠將你的顯示配置降低到最少。

這裡元件掃描我們通過在XML裡面使用Spring context名稱空間的元素來啟用。
配置如下:

<!-- 加了下面2局就可以直接使用spring註解 -->
<!-- 自動掃描的包名 -->
<context:component-scan base-package="com.tengj.demo" />
<!-- 預設的註解對映的支援 -->
<mvc:annotation-driven />複製程式碼

context:component-scan裡面的 base-package指明瞭被掃描的包的路徑是在com.tengj.demo下面的所有類
其中mvc:annotation-driven 是開啟預設的註解對映的支援,這樣就能認到被使用的註解。
我們在com.tengj.demo下面建立一個UserController控制類:

@Controller
public class UserController{
    @Autowired
    UserService userService;
}複製程式碼

UserService是我們的一個介面,程式碼如下:

public interface UserService {
    public void addUser() throws Exception;
}複製程式碼

UserServiceImpl是UserService的實現類:

@Service("userService")
public class UserServiceImpl implements UserService{
@Override
    public void addUser() throws Exception {
        System.out.println("新增使用者");
    }
}複製程式碼

寫個單元測試類來驗證這個userService是否已經自動注入了

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath:spring/applicationContext.xml"})
public class UserConTrollerTest {
    @Autowired
    UserService userService;

    @Test
    public void checkServiceIsNull(){
        Assert.assertNotNull(userService);
    }
}複製程式碼

UserConTrollerTest使用了Spring的SpringJUnit4ClassRunner,以便在測試開始的時候自動建立Spring的應用上下文,註解@ContextConfiguration會告訴它需要在UserConTrollerTest中載入配置。所以讀取applicationContext.xml配置檔案,配置檔案裡面有這個啟用自動掃描的元素。
為了證明這一點,在測試程式碼中有一個UserService型別的屬性,並且這個屬性帶有@Autowired註解,以便於將UserService bean注入到測試程式碼之中。最後,會有一個簡單的測試方法斷言userService屬性不為null。如果它不為null的話,就意味著Spring能夠發現UserService類,自動在Spring上下文中將其建立為bean並將其注入到測試程式碼之中。
在程式碼中右鍵執行Junit Test,如果執行如下是綠色的就表示成功。

SpringMVC 乾貨系列:從零搭建 SpringMVC+mybatis(三):Spring 兩大核心之 IOC/DI 學習 | 掘金技術徵文

總結

這就是一個簡單的DI注入測試,是不是覺得很方便,要注入什麼屬性只要定義一下屬性。剩下都交給Spring容器來搞定。Junit單元測試寫法後續會專門寫一篇來介紹,這也是非常重要的一個驗證自己所寫程式碼是否正確的手段。


一直覺得自己寫的不是技術,而是情懷,一篇篇文章是自己這一路走來的痕跡。靠專業技能的成功是最具可複製性的,希望我的這條路能讓你少走彎路,希望我能幫你抹去知識的蒙塵,希望我能幫你理清知識的脈絡,希望未來技術之巔上有你也有我。

剛來掘金當專欄作者,歡迎關注,後面陸續分享更多幹貨文章

掘金技術徵文第三期:聊聊你的最佳實踐

相關文章