初識Spring —— Bean的裝配(二)

這篇文章來自個人博客spring

正文以前

上一篇文章已經介紹了 Bean 的基本概念,因此今天這篇文章是基於上一篇中 Bean 的三種裝配方式來進一步探討,內容中會穿插着基礎的依賴注入的概念express

主要內容bash

  1. 自動裝配
  2. 使用 XML 裝配
  3. 使用 Java 裝配

正文

1. 自動裝配

  • Bean 的命名

上一篇文章中使用註解定義 Bean 的時候都是在類的定義上加註解,小寫的類名做爲 Bean 的 ID,可是咱們能夠本身命名 Bean:學習

設置組件的值爲 Bean 的名字,若是這麼作了,在測試中就找不到名爲「student」的 Bean 了:測試

將測試中獲取的 Bean 的名字改成「myBean」以後就能經過測試了ui

  • 組件掃描

上次講到了組件掃描,設置組件掃描的方式有兩種:spa

  1. XML 文件中配置
  2. Java 配置類中添加註解

咱們再還原 student 這個 Bean 的狀態,也就是在類的定義上加一個註解 @Component3d

在配置文件中添加組建掃描:code

這個是上次講過的,就再也不多說,而後來看看 Java 配置類的組件掃描:cdn

添加的註解 @Component 帶一個參數,指定了掃描的包的位置,就至關於 XML 配置文件中的 base-package 屬性

若是不填寫參數,就掃描此文件所在的包,在這裏,咱們掃描名爲「bean」的包,點擊註解左邊的那個按鈕就能跳轉到 Student 類(bean 包中)

  • 進階自動裝配

此處引用《Spring實戰》的一句話:

簡單來講,自動裝配就是讓 Spring 自動知足 Bean 依賴的一種方法,在知足依賴的過程當中,會在 Spring 應用上下文中尋找匹配某個 Bean 需求的其餘 Bean

咱們這裏添加一個接口 Book,至於爲何用接口而不用實現類,由於咱們後文要對這個接口作多個實現:

而後建立一個實現了 Book 接口的類,而且將其做爲一個 Bean:

既然是自動裝配,確定要用到註解 @Autowired,那麼,這個註解能夠用在什麼地方呢?

  • 實例化
  • 構造器(構造器注入)
  • Setter 方法(設值注入)

第一點以前說過,在實例化時候添加這個註解進行自動裝配

怎麼在構造器上使用呢?

咱們修改一下 Student 類:

在構造 Student 的時候,我將一個 Book 類注入,由於咱們剛纔已經有了 Book 類的實現,因此這裏注入的是 englishBook 這個 Bean

須要注意的是:Spring 在建立 student 這個 Bean 的時候,會傳入一個 Book 類型的 Bean

有兩種狀況會致使拋出異常,沒有所匹配的 Bean 或有多個所匹配的 Bean

爲了驗證第一種狀況,我將 EnglishBook 的 @Component 註解去掉,這樣子就沒有 Book 類型的 Bean 了

  • @Autowired 的屬性值 required 設置爲 false,可避免圖中的缺乏 Bean 的狀況:

運行測試以後,看到兩條主要的錯誤信息:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'student' defined in file [C:\Users\94545\Desktop\Developer Folder\Java Test Folder\springtest\out\production\springtest\bean\Student.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'bean.Book' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'bean.Book' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

首先是名爲「student」 的 Bean 的構造器中的依賴關係出錯了,第二是沒有 Book 類型的 Bean,致使 Student 的 Bean 的構造器中條件不符合

爲了驗證第二種狀況,我將代碼還原,而且建立另外一個 Book 類型的 Bean:mathBook,在此狀況下,測試是不會經過的,由於沒有單一符合條件的 Bean

  • 如有多個符合要求的 Bean,就須要一下方案來消除歧義:
  1. 標識首選的一個 Bean:@Primary 註解

測試後,證明了註解有效:

  1. 在須要注入的地方使用 @Qualifier註解:

這個註解對於構造器注入是不可用的,接下來在 Setter 方法上裝配的時候再講解

怎麼在 Setter 方法上使用呢?

咱們須要修改一下 Student 類,而且暫時隱藏一下 mathBook 這個 Bean:

帶有 @Autowired 註解,在實例化時可以自動匹配 Book 類型的 Bean:

關於 Setter 方法和構造器來裝配 Bean,就目前的學習狀況來講,只有一點區別,若是有多個不一樣類型的 Bean,使用構造器可以指定裝配的順序

如今咱們還原 mathBook 這個 Bean,若是出現上述的兩個可能拋出異常的狀況,這裏有兩種解決方式:

  1. @Primary 註解:

和上述相似,很少說

  1. 在須要注入的地方使用限定符,也就是 @Qualifier註解:

而後就能打印出英語書的信息(不截圖了)

這個註解有一點靈活的地方就是,可以在 Bean 的定義上設置限定符,也就是說,限定符不必定要是 Bean 的名字,作個測試:

這時候,若是還使用 englishBook 做爲限定符,也可以定位到這個 Bean,可是咱們用自定義的限定符也能夠,修改 Setter 方法上的限定符,進行測試:

證實使用 testQualifier 做爲限定符也能獲得結果

2. 使用 XML 裝配

使用 XML 裝配也有分構造器注入仍是設值注入(Setter)方法,接下來的前三個使用的是構造器注入

1. 構造器注入
傳遞 Bean 的引用

將自動裝配部分添加的註解取消掉,把代碼還原成初始狀態,而後咱們開始使用 XML 裝配:

暫時不配置 mathBook 這個 Bean,並修改 StudentTest 的上下文配置信息:

最後即是 Bean 的配置文件:

首先建立 englishBook 這個 Bean,在建立 student 這個 Bean,這裏有一個元素

<constructor-arg ref=""/>
複製代碼

由於我在 student 的構造器中有一個名叫 englishBook 的Bean 做爲參數,因此 Spring 會建立一個 ID 爲 englishBook 的Bean,並將其引用傳遞至 student 的構造器中,ref 屬性代表了傳遞引用的 Bean 的ID

傳遞字符串

若是我在 student 的構造器中傳入的不是某個 Bean 的引用,而是某個字符串呢?

修改 XML 文件中的配置信息:

value 屬性表示的是構造器中的字面量的值,能夠是字符串、數字或布爾值等

而後測試一下:

證實字面量被成功注入了

傳遞列表

一個學生不可能只有一本書,因此咱們要考慮,如何傳入列表呢?

首先咱們先修改 Student 類,傳入的參數不只是字符串,還有一個存放書本的列表:

而後在 XML 文件中配置 Bean:

<bean id="englishBook" class="bean.EnglishBook"/>
    <bean id="mathBook" class="bean.MathBook"/>
複製代碼

最後配置 student 這個 Bean,而且配置構造器參數:

<bean id="student" class="bean.Student">
        <constructor-arg value="I have some books"/>
        <constructor-arg>
            <list>
                <ref bean="englishBook"/>
                <ref bean="mathBook"/>
            </list>
        </constructor-arg>
    </bean>
複製代碼

第一個參數是字符串,第二個是 Book 類型的 List,列表中存放的是剛纔建立的兩個 Bean 的引用,而後來進行測試:

若是列表中也存放字符串,而不是引用,在元素中使用屬性來代替屬性

2. 設值注入

修改 Student 類和 Bean 配置文件:

而後在 Bean 的配置文件中加上這麼一句:

<bean id="student" class="bean.Student">
        <property name="book" ref="englishBook"/>
    </bean>
複製代碼

屬性是爲 Setter 方法提供服務的,和上述的屬性所提供的服務是同樣的,在這個語句中,我在 book 中注入了 ID 爲 englishBook 的 Bean 的引用,而後測試,會輸出英語書的信息:

關於字面量和列表的注入,其實和構造器注入是相似的,將屬性替換爲,只不過,設置注入須要設置屬性名,也就是將 a Bean 的引用(或字面量或集合)注入到 b 屬性中,就再也不詳述

3. 使用 Java 裝配

除了使用 XML,還可以使用 Java 代碼來裝配 Bean 而且達到依賴注入的目的

因此咱們須要先修改測試中的上下文配置信息:

@ContextConfiguration(classes = StudentConfig.class)
複製代碼

再將 Student 類改回構造器注入的類型:

使用 Java 進行 Bean 的裝配在上一篇文章中已經提到,這裏就說一說依賴注入的實現:

在 Java 配置類中定義兩個 Bean:

在 student 中使用構造器注入了 englishBook 這個 Bean,運行測試,將會獲得英語書的輸出:

總結

其實,這一篇文章把 Bean 的裝配和依賴注入混合起來將了,可能有些人會以爲亂,可是三種方式其實從思路來講是相似的,經過認真地閱讀這兩篇關於 Bean 的介紹,就能對 Spring 的 DI 以及 IoC 有一個基本瞭解

DI(Dependency Injection)稱爲依賴注入,通俗的說,是在運行時,動態地知足某個對象對其餘對象的需求,用上面的例子來講,student 在運行時須要 Book 類型的 Bean 做爲依賴,我就給它注入一個 Bean,叫作 englishBook,這就可以叫作依賴注入

IoC(Inversion of Control)稱爲控制反轉,在上面作的全部測試中,我都沒有手動建立某個對象的實例,好比說注入一個列表,我甚至都沒有建立一個列表的實例,那麼爲何還會經過測試呢?由於 Spring 幫我在程序運行時建立了各個 Bean 的實例

IoC 可以由 DI 來實現,也就是說,程序中的各個組件之間的依賴關係都是由 Spring 來管理的,這就稱做控制反轉,這是 Spring 的核心

接下來還陸續會有文章來說述這一律念

相關文章
相關標籤/搜索