IoC 容器

簡介

Spring 的控制反轉 (IoC) 容器。IoC 也稱為依賴注入 (DI)。這是一個過程。對象僅通過構造函數參數、工廠方法的參數設置的屬性來定義它們的依賴關係, 然後容器在創建 bean 時注入這些依賴項。

在IoC模式下,控制權發生了反轉,即從開發人員自己創建轉移到了IoC容器,所有組件不再由應用程序自己創建和配置,而是由IoC容器負責,所以叫控制反轉。

BeanFactory 接口提供了一種高級配置機制,能夠管理任何類型的對象。 ApplicationContext 是 的子接口BeanFactory。它補充説:

  • 更容易與 Spring 的 AOP 功能集成
  • 消息資源處理(用於國際化)
  • 活動發佈
  • 應用層特定上下文,例如WebApplicationContext 用於 Web 應用程序的上下文。

簡而言之,它BeanFactory提供了配置框架和基本功能,並ApplicationContext增加了更多的企業特定功能。

在 Spring 中,由 Spring IoC 容器管理的對象稱為 bean。bean 是由 Spring IoC 容器實例化、組裝和管理的對象。否則,bean 只是應用程序中的眾多對象之一。Bean 以及它們之間的依賴關係反映在容器使用的配置元數據中。

容器概述

ApplicationContext`接口代表 Spring IoC 容器,負責實例化、配置和組裝 bean。容器通過讀取配置元數據來獲取關於要實例化、配置和組裝哪些對象的指令。配置元數據以 XML、Java 註釋或 Java 代碼表示。它允許您表達組成應用程序的對象以及這些對象之間豐富的相互依賴關係。

ApplicationContextSpring 提供了該接口的幾個實現。在獨立應用程序中,通常會創建ClassPathXmlApplicationContext 或的實例 FileSystemXmlApplicationContext。雖然 XML 一直是定義配置元數據的傳統格式,但您可以通過提供少量 XML 配置來以聲明方式啓用對這些附加元數據格式的支持,從而指示容器使用 Java 註釋或代碼作為元數據格式。

配置元數據

Spring IoC 容器使用一種形式的配置元數據。此配置元數據表示您作為應用程序開發人員如何告訴 Spring 容器實例化、配置和組裝應用程序中的對象。

配置元數據傳統上以簡單直觀的 XML 格式提供,本章大部分內容都使用這種格式來傳達 Spring IoC 容器的關鍵概念和特性。

有關在 Spring 容器中使用其他形式的元數據的信息,請參閲:

  • 基於註解的配置:Spring 2.5 引入了對基於註解的配置元數據的支持。
  • 基於 Java 的配置

Spring 配置包含容器必須管理的至少一個,通常是多個 bean 定義。基於 XML 的配置元數據將這些 bean 配置為<bean/>頂級元素內的<beans/>元素。Java 配置通常@Bean在類中使用 -annotated 方法@Configuration

實例化一個容器

提供給構造函數的一個或多個位置路徑ApplicationContext是資源字符串,允許容器從各種外部資源(例如本地文件系統、Java 等)加載配置元數據。

ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
編寫基於 XML 的配置元數據

讓 bean 定義多個 XML 文件會很有用。通常,每個單獨的 XML 配置文件都代表架構中的一個邏輯層或模塊。

<beans>
    <import resource="services.xml"/>
    <import resource="resources/messageSource.xml"/>
 
    <bean id="bean1" class="..."/>
</beans>

使用容器

ApplicationContext是一個高級工廠的接口,能夠維護不同 bean 及其依賴項的註冊表。

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

Bean概述

Spring IoC 容器管理一個或多個 bean。這些 bean 是使用您提供給容器的配置元數據創建的。

在容器本身中,這些 bean 定義表示為BeanDefinition 對象,其中包含(以及其他信息)以下元數據:

  • 一個包限定的類名:通常是被定義的 bean 的實際實現類。
  • Bean 行為配置元素,它説明 bean 在容器中的行為方式(範圍、生命週期回調等)。
  • 對 bean 完成工作所需的其他 bean 的引用。這些引用也稱為協作者或依賴項。
  • 要在新創建的對象中設置的其他配置設置——例如,池的大小限制或在管理連接池的 bean 中使用的連接數。

注意:

Bean 元數據和手動提供的單例實例需要儘早註冊,官方不支持在運行時註冊新 bean,並可能導致併發訪問異常、bean 容器中的狀態不一致。

命名 Bean

每個 bean 都有一個或多個標識符。這些標識符在承載 bean 的容器中必須是唯一的。一個 bean 通常只有一個標識符。但是,如果它需要多個,則可以將多餘的視為別名。

在基於 XML 的配置元數據中,您可以使用id屬性、name屬性或兩者來指定 bean 標識符。

您不需要為 bean 提供 name或 id。如果您不顯式提供 nameid,則容器會為該 bean 生成一個唯一名稱。但是,如果您想通過名稱引用該 bean,通過使用ref元素或服務定位器樣式查找,您必須提供名稱。

實例化 Bean

bean 定義本質上是創建一個或多個對象的方法。

如果您使用基於 XML 的配置元數據,您可以在元素的class屬性中指定要實例化的對象的類型。

您可以通過以下兩種方式之一使用該屬性:

  • 通常,在容器本身通過反射調用其構造函數直接創建 bean 的情況下,指定要構造的 bean 類,有點等價於 Java 代碼中的new運算符。
  • static指定包含被調用以創建對象 的工廠方法的實際類,在不太常見的情況下,容器調用static類上的工廠方法來創建 bean。調用static工廠方法返回的對象類型可能是同一個類,也可能完全是另一個類。
使用構造函數進行實例化

當您通過構造方法創建 bean 時,所有普通類都可以被 Spring 使用併兼容。也就是説,正在開發的類不需要實現任何特定的接口或以特定的方式進行編碼。只需指定 bean 類就足夠了。但是,根據您用於該特定 bean 的 IoC 類型,您可能需要一個默認(空)構造函數。

<bean id="exampleBean" class="examples.ExampleBean"/>
使用靜態工廠方法進行實例化

在定義使用靜態工廠方法創建的 bean 時,使用class 屬性指定包含static工廠方法的類,使用命名屬性factory-method指定工廠方法本身的名稱。您應該能夠調用此方法(使用可選參數,如後所述)並返回一個活動對象,該對象隨後被視為是通過構造函數創建的。這種 bean 定義的一種用途是static在遺留代碼中調用工廠。

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>
使用實例工廠方法進行實例化

與通過靜態工廠方法進行實例化類似,使用實例工廠方法進行實例化會從容器中調用現有 bean 的非靜態方法來創建新 bean。要使用此機制,請將class屬性留空,並在factory-bean屬性中指定當前(或父級或祖先)容器中包含要調用以創建對象的實例方法的 bean 的名稱。factory-method使用屬性設置工廠方法本身的名稱。以下示例顯示瞭如何配置這樣的 bean:

<!-- the factory bean, which contains a method called createInstance() -->
<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<!-- the bean to be created via the factory bean -->
<bean id="clientService"
    factory-bean="serviceLocator"
    factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}