Java Spring 控制反轉(IOC)容器詳解

IoC 容器是 Spring 的核心,也可以稱為 Spring 容器。Spring 通過 IoC 容器來管理對象的實例化和初始化,以及對象從創建到銷毀的整個生命周期。

Spring 中使用的對象都由 IoC 容器管理,不需要我們手動使用 new 運算符創建對象。由 IoC 容器管理的對象稱為 Spring Bean,Spring Bean 就是 Java 對象,和使用 new 運算符創建的對象沒有區別。

Spring 通過讀取 XML 或 Java 註解中的信息來獲取哪些對象需要實例化。

Spring 提供 2 種不同類型的 IoC 容器,即 BeanFactory 和 ApplicationContext 容器。

什麼是容器?

容器是一種為某種特定組件的運行提供必要支持的一個軟件環境。例如,Tomcat就是一個Servlet容器,它可以為Servlet的運行提供運行環境。類似Docker這樣的軟件也是一個容器,它提供瞭必要的Linux環境以便運行一個特定的Linux進程。

通常來說,使用容器運行組件,除瞭提供一個組件運行環境之外,容器還提供瞭許多底層服務。例如,Servlet容器底層實現瞭TCP連接,解析HTTP協議等非常復雜的服務,如果沒有容器來提供這些服務,我們就無法編寫像Servlet這樣代碼簡單,功能強大的組件。早期的JavaEE服務器提供的EJB容器最重要的功能就是通過聲明式事務服務,使得EJB組件的開發人員不必自己編寫冗長的事務處理代碼,所以極大地簡化瞭事務處理。

無侵入容器

在設計上,Spring的IoC容器是一個高度可擴展的無侵入容器。所謂無侵入,是指應用程序的組件無需實現Spring的特定接口,或者說,組件根本不知道自己在Spring的容器中運行。這種無侵入的設計有以下好處:

1.應用程序組件既可以在Spring的IoC容器中運行,也可以自己編寫代碼自行組裝配置;

2.測試的時候並不依賴Spring容器,可單獨進行測試,大大提高瞭開發效率。

IOC控制反轉

Spring提供的容器又稱為IoC容器,什麼是IoC?

Ioc—Inversion of Control,即“控制反轉”,不是什麼技術,是一個概念,是一種思想。指將傳統上由程序代 碼直接操控的對象調用權交給容器,通過容器來實現對象的裝配和管理。控制反轉就是對對象控制權的轉移,從程序代碼本身反轉到瞭外部容器。通過容器實現對象的裝配和管理。通俗點講,將對象的創建權交給spring,我們需要new對象,則由spring幫我們創建,然後供我們使用。

那麼必然的我們需要創建一個容器,同時需要一種描述來讓容器知道需要創建的對象與對象的關系。這個描述最具體表現就是我們可配置的文件。IoC的實質是如何管理對象,傳統意義上我們使用new方式來創建對象,但在企業應用開發的過程中,大量的對象創建都在程序中維護很容易造成資源浪費,並且不利於程序的擴展。

其實現方式多種多樣。當前比較流行的實現方式是依賴 註入。應用廣泛。

依賴:classA 類中含有 classB 的實例,在 classA 中調用 classB 的方法完成功能,即 classA 對 classB 有依賴。

IOC理論推導

傳統應用程序開發的弊端

在理解IoC之前,我們先看看通常的Java組件是如何協作的。

我們先用我們原來的方式寫一段代碼 .

1、先寫一個UserDao接口

在這裡插入圖片描述

2、再去寫Dao的實現類

public class UserDaoOneImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("One獲取用戶數據");
  }
}

3、然後去寫UserService的接口

在這裡插入圖片描述

4、最後寫Service的實現類

在這裡插入圖片描述

5、測試一下

在這裡插入圖片描述

6、再回到UserDao接口

在這裡插入圖片描述

把Userdao的實現類增加一個 .

public class UserDaoMyTwoImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Two獲取用戶數據");
  }
}

7、我們就需要去service實現類裡面修改對應的實現

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoTwo();
   @Override
   public void getUser() {
       userDao.getUser();
  }
}

在假設, 我們再增加一個Userdao的實現類 .

public class UserDaoThreeImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Three獲取用戶數據");
  }
}

那麼我們要使用Three , 又需要去service實現類裡面修改對應的實現 . 假設我們的這種需求非常大 , 這種方式就根本不適用瞭, 甚至反人類對吧 , 每次變動 , 都需要修改大量代碼 . 這種設計的耦合性太高瞭, 牽一發而動全身 .

“註入”機制

註入應用程序某個對象,應用程序依賴的對象

依賴註入可以通過set()方法實現。但依賴註入也可以通過構造方法實現。Spring的IoC容器同時支持屬性註入和構造方法註入,並允許混合使用。

我們可以在需要用到他的地方 , 不去實現它 , 而是留出一個接口 , 利用set , 我們去代碼裡修改下 .

在這裡插入圖片描述

@Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   service.setUserDao( new UserDaoTwoImpl() );
   service.getUser();
   //那我們現在又想添加Three去實現呢
   service.setUserDao( new UserDaoThreeImpl() );
   service.getUser();
}

以前所有東西都是由程序去進行控制創建 , 而現在是由我們自行控制創建對象 , 把主動權交給瞭調用者 . 程序不用去管怎麼創建,怎麼實現瞭 . 它隻負責提供一個接口 .

這種思想 , 從本質上解決瞭問題 , 我們程序員不再去管理對象的創建瞭 , 更多的去關註業務的實現 . 耦合性大大降低 . 這也就是IOC的原型 !

小結

傳統程序設計如圖,都是主動去創建相關對象然後再組合起來:

在這裡插入圖片描述

沒有什麼是加一層解決不瞭的

在這裡插入圖片描述

當有瞭IoC/DI的容器後,在客戶端類中不再主動去創建這些對象瞭

IOC本質

IoC是Spring框架的核心內容,使用多種方式完美的實現瞭IoC,可以使用XML配置,也可以使用註解,新版本的Spring也可以零配置實現IoC。

Spring容器在初始化時先讀取配置文件,根據配置文件或元數據創建與組織對象存入容器中,程序使用時再從Ioc容器中取出需要的對象。

在這裡插入圖片描述

控制反轉是一種通過描述(XML或註解)並通過第三方去生產或獲取特定對象的方式。在Spring中實現控制反轉的是IoC容器,其實現方法是依賴註入(Dependency Injection,DI)。

DI(依賴註入)

IoC的一個重點是在系統運行中,動態的向某個對象提供它所需要的其他對象。這一點是通過DI(Dependency Injection,依賴註入)來實現的。 比如對象A需要操作數據庫,以前我們總是要在A中自己編寫代碼來獲得一個Connection對象,有瞭 spring我們就隻需要告訴spring,A中需要一個Connection,至於這個Connection怎麼構造,何時構造,A不需要知道。在系統運行時,spring會在適當的時候制造一個Connection,然後像打針一樣,註射到A當中,這樣就完成瞭對各個對象之間關系的控制。A需要依賴 Connection才能正常運行,而這個Connection是由spring註入到A中的,依賴註入的名字就這麼來的。那麼DI是如何實現的呢? Java 1.3之後一個重要特征是反射(reflection),它允許程序在運行的時候動態的生成對象、執行對象的方法、改變對象的屬性,spring就是通過反射來實現註入的。

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: