Spring 中的 Bean

2023-06-23 21:00:30

前言

歡迎來到本篇文章,鴿了好久了,今天繼續寫下 Spring 的內容:Spring 中 Bean 的基本概念、基本寫法和 3 種範例化 Bean 的方式等。

什麼是 Bean?

我們回顧下,什麼是 Bean?這在上一篇文章 Spring 核心概念之一 IoC 中說過了,簡而言之,一句話:被 Spring IoC 管理的物件,就是 Bean。

一個 Spring IoC 容器中管理著一個或多個 Bean,這些 Bean 是由我們提供給容器的設定後設資料建立的(比如以 XML <bean /> 形式定義的 Bean)。

「Bean Definition」的屬性

在容器本身中,這些 Bean 定義被表示為 BeanDefinition 物件,它包含(除其他資訊外)以下後設資料(metadata)。

  • 一個全路徑類名:比如 cn.god23bin.demo.controller.DemoController,這就是 Bean Definition 的實際實現類。
  • Bean 的行為設定元素:它說明了 Bean 在容器中的行為方式(比如 scope、生命週期回撥等等)。
  • 對其他 Bean 的參照:這些被參照的 Bean 被稱為共同作業者或依賴(collaborators or dependencies)。
  • 其他設定的設定:比如,資料庫連線池的大小限制或使用的連線數。

這些後設資料對應著每個 Bean Definition 的一組屬性。下表描述了這些屬性:

屬性 解釋…
Class 該屬性是必需的,它指定了用於建立 bean 的 bean 類。
Name 該屬性唯一地指定 bean 識別符號。 在基於 XML 的設定後設資料中,我們可以使用 id 或 name 屬性來指定 bean 識別符號。
Scope 該屬性指定從特定 bean 定義建立的物件的範圍,將在 bean 範圍一章中討論。
Constructor arguments 這用於注入依賴關係,將在後續章節中討論。
Properties 這用於注入依賴關係,將在後續章節中討論。
Autowiring mode 這用於注入依賴關係,將在後續章節中討論。
Lazy initialization mode 懶載入模式,讓 bean 告訴 IoC 容器在第一次被請求時建立一個 bean 範例,而不是在啟動時。
Initialization method 在容器設定了 bean 上的所有必要屬性之後呼叫的回撥。 它將在 bean 生命週期章節中討論。
Destruction method 當包含 bean 的容器被銷燬時要使用的回撥。 它將在 bean 生命週期章節中討論。

Bean 的命名

以 XML 作為設定後設資料的方式中,Bean 定義的基本格式是這樣寫的:

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

    <bean id="..." class="...">  
        <!-- 該 bean 的共同作業者和設定寫在此處 -->
    </bean>

    <bean id="..." class="...">
        <!-- 該 bean 的共同作業者和設定寫在此處 -->
    </bean>

    <!-- 更多的 bean 定義寫在此處 -->

</beans>

XML 中類似 <bean/> 由尖括號組成的寫法,一般稱為「標籤」或者「元素」,在後面的說法中,可能有時出現標籤的說法或者元素的說法,實際上都是指同一個東西,後續便不再說明

我們可以看到,bean 標籤有 idclass 屬性。

這個 id 是每個 Bean 都有的一個識別符號(identifier),這些識別符號在 Spring IoC 容器中必須是唯一的

一個 Bean 一般只有一個識別符號。如果它需要一個以上的識別符號,那麼多餘的識別符號可以被視為別名

在基於 XML 的設定後設資料中,我們可以使用 id 屬性、name 屬性或兩者來指定 Bean 的識別符號。

命名習慣

習慣上,這裡對於 Bean 定義的命名和對於我們命名 Java 類中的屬性名是一樣的,就是駝峰命名,小寫字母開頭。比如 userServiceuserDaologinController 等等。

還有,如果想起多個別名,那麼用 name 屬性指定別名是什麼,比如 name="別名1,別名2,別名3",多個別名之間可以用英文逗號、英文分號或者空格分隔。

Bean 的別名

除了使用 Bean 定義中的 name 屬性來對 Bean 起別名,還可以使用 alias 標籤給 Bean 起別名:

<bean id = "userService" name="userServiceName" ... ></bean>
<alias name="userServiceName" alias="userServiceAliasName" />

這樣,名為 userServiceName 的 Bean 也有了另一個名字:userServiceAliasName

Spring 範例化 Bean 的 3 種方式

Spring 可以通過 3 種方式來為我們建立 Bean 物件,建立的物件是根據我們定義的設定後設資料來進行建立的。

這 3 種方式分別是:

  1. 通過構造方法範例化
  2. 通過靜態工廠方法範例化
  3. 通過範例工廠方法範例化

在上面的 Bean 定義的屬性中,我們也看到了,在 <bean /> 中有一個 class 屬性,就是用來指定要範例化的物件的型別的。一般情況下,這個 class 屬性是必須寫的,除非是通過範例工廠方法範例化的 Bean,那麼它的 Bean 定義可以不需要 class 屬性

1. 通過構造方法範例化

以 XML 為設定後設資料為例,在預設的情況下,我們定義的 Bean 都是以構造方法來範例化 Bean 物件的。

這些交給 Spring 管理的 Bean,不需要實現 Spring 的某某介面或者繼承 Spring 的某某類,只需要有一個無參的構造方法,就可以了。

這裡也是 Spring 低侵入的特點,我們的類根本不需要去實現 Spring 特定的介面或繼承特定的類進而實現 IoC 的功能。

<bean id="fans" class="cn.god23bin.demo.domain.entity.Fans">
    <property name="name" value="god23bin" />
</bean>

以上面這個例子來說,這樣定義的 Bean 就是通過 cn.god23bin.demo.domain.entity.Fans 的構造方法範例化的:

package cn.god23bin.demo.domain.entity;

public class Fans {
    private String name;

    public Fans() {
        System.out.println("粉絲無參構造方法被呼叫了!");
    }

    // 省略 getter 和 setter
}

從 Spring IoC 容器中獲取被管理的 Fans 物件,這個過程,Spring 就會根據設定後設資料去使用構造方法範例化 Fans 物件。

測試:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Fans fans = applicationContext.getBean(Fans.class);
System.out.println("fans name: " + fans.getName());

輸出:

粉絲無參構造方法被呼叫了!
fans name: god23bin

2. 通過靜態工廠方法範例化

假設我們有一些物件是從靜態工廠中獲取物件的,有一個靜態工廠類,類中定義了一個靜態方法,該方法是建立物件的:

package cn.god23bin.demo.domain.entity.factory;

import cn.god23bin.demo.domain.entity.Fans;

public class FansStaticFactory {
    // 返回 Fans 物件的靜態方法
    public static Fans createFansInstance() {
        System.out.println("粉絲靜態工廠!");
        Fans fans = new Fans();
        fans.setName("練習兩年半 | 你幹嘛哎喲~~");
        return fans;
    }
}

接著在設定後設資料中定義 Bean,將通過呼叫工廠的靜態方法來建立 Bean 物件,使用 class 屬性指定包含了靜態工廠方法的類,使用 factory-method 屬性指定建立物件的靜態方法:

<bean id="fans" class="cn.god23bin.demo.domain.entity.factory.FansStaticFactory" factory-method="createFansInstance" />

測試:

ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Fans fans = applicationContext.getBean(Fans.class);
System.out.println("fans name: " + fans.getName());

輸出:

粉絲靜態工廠!
粉絲無參構造方法被呼叫了!
fans name: 練習兩年半 | 你幹嘛哎喲~~

3. 通過範例工廠方法範例化

範例工廠:

package cn.god23bin.demo.domain.entity.factory;

import cn.god23bin.demo.domain.entity.Fans;

public class FansFactory {
    public FansFactory() {
    }

    public Fans createFansInstance() {
        System.out.println("粉絲工廠");
        Fans fans = new Fans();
        fans.setName("練習兩年半 | 你幹嘛哎喲~~ | 記得關注我噢~");
        return fans;
    }
}

和靜態工廠範例化 Bean 物件類似,我們這裡用範例廠方法進行 Bean 的範例化,從 Spring IoC 容器中呼叫現有工廠 Bean 的非靜態方法來建立一個新的 Bean。

這裡需要注意 Fans 這個 Bean 的 class 屬性是不需要的。

<!-- 設定範例工廠 Bean,該物件包含了建立 Fans 物件的名為 createFansInstance 的方法 -->
<bean id="fansFactory" class="cn.god23bin.demo.domain.entity.factory.FansFactory">
    <!-- 工廠的其他需要的依賴物件就設定在這裡 -->
</bean>

<!-- 這個 Bean 將通過範例工廠建立 -->
<bean id="fans" factory-bean="fansFactory" factory-method="createFansInstance" />

總結

以上,就是本文的所有內容,主要介紹了 Spring 中 Bean 的概念和 Bean 的定義屬性。

Bean 由設定後設資料建立,比如以XML形式定義的 Bean。Bean 在容器中由 BeanDefinition 物件表示,它包含類名、行為設定元素、對其他 Bean 的參照以及其他設定設定等後設資料屬性。

Bean 的命名方式一般就是駝峰命名的。在基於XML的設定後設資料中,可以使用 id 屬性或 name 屬性來指定 Bean 的識別符號,Bean 的別名可以使用 alias 標籤進行定義。

最後,我們說了 Spring 範例化 Bean 的三種方式:通過構造方法範例化、通過靜態工廠方法範例化和通過範例工廠方法範例化。

當然,Bean 的內容不止這些,本文是對 Bean 的初步介紹。下一篇我們將介紹 Bean 之間的依賴關係,通過依賴注入來實現 Bean 之間的相互依賴。

最後的最後

希望各位螢幕前的靚仔靚女們給個三連!你輕輕地點了個贊,那將在我的心裡世界增添一顆明亮而耀眼的星!

咱們下期再見!