spring——控制反轉(IoC)—— 與 ——依賴注入(DI)
控制反轉(IoC)
在傳統的 Java 應用中,一個類想要呼叫另一個類中的屬性或方法,通常會先在其程式碼中通過 new Object() 的方式將後者的物件創建出來,然後才能實現屬性或方法的呼叫。
為了方便理解和描述,我們可以將前者稱為“呼叫者”,將後者稱為“被呼叫者”。
也就是說,呼叫者掌握著被呼叫者物件建立的控制權。
但在 Spring 應用中,Java 物件建立的控制權是掌握在 IoC 容器手裡的,其大致步驟如下。
- 開發人員通過 XML 配置檔案、註解、Java 配置類等方式,對 Java 物件進行定義,例如在 XML 配置檔案中使用 <bean> 標籤、在 Java 類上使用 @Component 註解等。
- Spring 啟動時,IoC 容器會自動根據物件定義,將這些物件建立並管理起來。這些被 IoC 容器建立並管理的物件被稱為 Spring Bean。
- 當我們想要使用某個 Bean 時,可以直接從 IoC 容器中獲取(例如通過 ApplicationContext 的 getBean() 方法),而不需要手動通過程式碼(例如 new Obejct() 的方式)建立。
IoC 帶來的最大改變不是程式碼層面的,而是從思想層面上發生了“主從換位”的改變。
原本呼叫者是主動的一方,它想要使用什麼資源就會主動出擊,自己建立;但在 Spring 應用中,IoC 容器掌握著主動權,呼叫者則變成了被動的一方,被動的等待 IoC 容器建立它所需要的物件(Bean)。
這個過程在職責層面發生了控制權的反轉,把原本呼叫者通過程式碼實現的物件的建立,反轉給 IoC 容器來幫忙實現,因此我們將這個過程稱為 Spring 的“控制反轉”。
IoC 是 Inversion of Control 的簡寫,譯為“控制反轉”,它不是一門技術,而是一種設計思想,是一個重要的面向物件程式設計法則,能夠指導我們如何設計出鬆耦合、更優良的程式。
Spring 通過 IoC 容器來管理所有 Java 物件的例項化和初始化,控制物件與物件之間的依賴關係。我們將由 IoC 容器管理的 Java 物件稱為 Spring Bean,它與使用關鍵字 new 建立的 Java 物件沒有任何區別。
IoC 容器是 Spring 框架中最重要的核心元件之一,它貫穿了 Spring 從誕生到成長的整個過程。
依賴注入(DI)
在瞭解了 IoC 之後,我們還需要了解另外一個非常重要的概念:依賴注入。
依賴注入(Denpendency Injection,簡寫為 DI)是 Martin Fowler 在 2004 年在對“控制反轉”進行解釋時提出的。
Martin Fowler 認為“控制反轉”一詞很晦澀,無法讓人很直接的理解“到底是哪裡反轉了”,因此他建議使用“依賴注入”來代替“控制反轉”。
在面向物件中,物件和物件之間是存在一種叫做“依賴”的關係。簡單來說,依賴關係就是在一個物件中需要用到另外一個物件,即物件中存在一個屬性,該屬性是另外一個類的物件。
例如,有一個名為 B 的 Java 類,它的程式碼如下。
- public class B {
- String bid;
- A a;
- }
從程式碼可以看出,B 中存在一個 A 型別的物件屬性 a,此時我們就可以說 B 的物件依賴於物件 a。而依賴注入就是就是基於這種“依賴關係”而產生的。
我們知道,控制反轉核心思想就是由 Spring 負責物件的建立。在物件建立過程中,Spring 會自動根據依賴關係,將它依賴的物件注入到當前物件中,這就是所謂的“依賴注入”。
依賴注入本質上是 Spring Bean 屬性注入的一種,只不過這個屬性是一個物件屬性而已。
IoC 的工作原理
在 Java 軟體開發過程中,系統中的各個物件之間、各個模組之間、軟體系統和硬體系統之間,或多或少都存在一定的耦合關係。
若一個系統的耦合度過高,那麼就會造成難以維護的問題,但完全沒有耦合的程式碼幾乎無法完成任何工作,這是由於幾乎所有的功能都需要程式碼之間相互協作、相互依賴才能完成。
因此我們在程式設計時,所秉承的思想一般都是在不影響系統功能的前提下,最大限度的降低耦合度。
IoC 底層通過工廠模式、Java 的反射機制、XML 解析等技術,將程式碼的耦合度降低到最低限度,其主要步驟如下。
- 在配置檔案(例如 Bean.xml)中,對各個物件以及它們之間的依賴關係進行配置;
- 我們可以把 IoC 容器當做一個工廠,這個工廠的產品就是 Spring Bean;
- 容器啟動時會載入並解析這些配置檔案,得到物件的基本資訊以及它們之間的依賴關係;
- IoC 利用 Java 的反射機制,根據類名生成相應的物件(即 Spring Bean),並根據依賴關係將這個物件注入到依賴它的物件中。
由於物件的基本資訊、物件之間的依賴關係都是在配置檔案中定義的,並沒有在程式碼中緊密耦合,因此即使物件發生改變,
我們也只需要在配置檔案中進行修改即可,而無須對 Java 程式碼進行修改,這就是 Spring IoC 實現解耦的原理。
==============================================================================================
IoC 容器的兩種實現
IoC 思想基於 IoC 容器實現的,IoC 容器底層其實就是一個 Bean 工廠。Spring 框架為我們提供了兩種不同型別 IoC 容器,它們分別是 BeanFactory 和 ApplicationContext。
---------------------------------------------------------------------------------------------------------------------------
ApplicationContext的3個實現類:
BeanFactory和ApplicationContext的區別