這篇文章來自個人博客spring
上一篇文章已經介紹了 Bean 的基本概念,因此今天這篇文章是基於上一篇中 Bean 的三種裝配方式來進一步探討,內容中會穿插着基礎的依賴注入的概念express
主要內容bash
- 自動裝配
- 使用 XML 裝配
- 使用 Java 裝配
上一篇文章中使用註解定義 Bean 的時候都是在類的定義上加註解,小寫的類名做爲 Bean 的 ID,可是咱們能夠本身命名 Bean:學習
設置組件的值爲 Bean 的名字,若是這麼作了,在測試中就找不到名爲「student」的 Bean 了:測試
將測試中獲取的 Bean 的名字改成「myBean」以後就能經過測試了ui
上次講到了組件掃描,設置組件掃描的方式有兩種:spa
咱們再還原 student 這個 Bean 的狀態,也就是在類的定義上加一個註解 @Component:3d
在配置文件中添加組建掃描:code
這個是上次講過的,就再也不多說,而後來看看 Java 配置類的組件掃描:cdn
添加的註解 @Component 帶一個參數,指定了掃描的包的位置,就至關於 XML 配置文件中的 base-package 屬性
若是不填寫參數,就掃描此文件所在的包,在這裏,咱們掃描名爲「bean」的包,點擊註解左邊的那個按鈕就能跳轉到 Student 類(bean 包中)
此處引用《Spring實戰》的一句話:
簡單來講,自動裝配就是讓 Spring 自動知足 Bean 依賴的一種方法,在知足依賴的過程當中,會在 Spring 應用上下文中尋找匹配某個 Bean 需求的其餘 Bean
咱們這裏添加一個接口 Book,至於爲何用接口而不用實現類,由於咱們後文要對這個接口作多個實現:
而後建立一個實現了 Book 接口的類,而且將其做爲一個 Bean:
既然是自動裝配,確定要用到註解 @Autowired,那麼,這個註解能夠用在什麼地方呢?
第一點以前說過,在實例化時候添加這個註解進行自動裝配
咱們修改一下 Student 類:
在構造 Student 的時候,我將一個 Book 類注入,由於咱們剛纔已經有了 Book 類的實現,因此這裏注入的是 englishBook 這個 Bean
須要注意的是:Spring 在建立 student 這個 Bean 的時候,會傳入一個 Book 類型的 Bean
有兩種狀況會致使拋出異常,沒有所匹配的 Bean 或有多個所匹配的 Bean
爲了驗證第一種狀況,我將 EnglishBook 的 @Component 註解去掉,這樣子就沒有 Book 類型的 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
測試後,證明了註解有效:
這個註解對於構造器注入是不可用的,接下來在 Setter 方法上裝配的時候再講解
咱們須要修改一下 Student 類,而且暫時隱藏一下 mathBook 這個 Bean:
帶有 @Autowired 註解,在實例化時可以自動匹配 Book 類型的 Bean:
關於 Setter 方法和構造器來裝配 Bean,就目前的學習狀況來講,只有一點區別,若是有多個不一樣類型的 Bean,使用構造器可以指定裝配的順序
如今咱們還原 mathBook 這個 Bean,若是出現上述的兩個可能拋出異常的狀況,這裏有兩種解決方式:
和上述相似,很少說
而後就能打印出英語書的信息(不截圖了)
這個註解有一點靈活的地方就是,可以在 Bean 的定義上設置限定符,也就是說,限定符不必定要是 Bean 的名字,作個測試:
這時候,若是還使用 englishBook 做爲限定符,也可以定位到這個 Bean,可是咱們用自定義的限定符也能夠,修改 Setter 方法上的限定符,進行測試:
證實使用 testQualifier 做爲限定符也能獲得結果
使用 XML 裝配也有分構造器注入仍是設值注入(Setter)方法,接下來的前三個使用的是構造器注入
將自動裝配部分添加的註解取消掉,把代碼還原成初始狀態,而後咱們開始使用 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 的引用,而後來進行測試:
若是列表中也存放字符串,而不是引用,在元素中使用屬性來代替屬性
修改 Student 類和 Bean 配置文件:
而後在 Bean 的配置文件中加上這麼一句:
<bean id="student" class="bean.Student">
<property name="book" ref="englishBook"/>
</bean>
複製代碼
屬性是爲 Setter 方法提供服務的,和上述的屬性所提供的服務是同樣的,在這個語句中,我在 book 中注入了 ID 爲 englishBook 的 Bean 的引用,而後測試,會輸出英語書的信息:
關於字面量和列表的注入,其實和構造器注入是相似的,將屬性替換爲,只不過,設置注入須要設置屬性名,也就是將 a Bean 的引用(或字面量或集合)注入到 b 屬性中,就再也不詳述
除了使用 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 的核心
接下來還陸續會有文章來說述這一律念