基本概念
自動裝配(autowire),意味着整個裝配過程是自動完成,而不再由我們手動去指定。
在 Spring 中自動裝配共有以下幾種方式:
名稱 | 說明 |
---|---|
no | 表示不使用自動裝配,此時必須手動指定依賴的 Bean |
byName | 根據屬性名自動裝配,預設會檢查整個容器中與屬性名稱相同的 Bean 辨別。 |
byType | 根據屬性的類型自動裝配,預設會檢查整個容器與屬性類型相同的 Bean。 |
constructor | 與 byType 相似,同樣是根據類型自動裝配,不同的是這裡比對的是構造參數的類型,主要用于 constructor(構造) 注入 |
default | 與 beans 标簽的 default-autowire 屬性有關 |
autodetect | 判斷 Bean 的構造方法是否存在構造參數,若有則采用 constructor 自動裝配,否則采用 byType 自動裝配。目前已過時,Spring 3.0 以後不再被使用 |
no
意味着不使用自動裝配,采用手動配置的方式。這裡以構造注入為例,介紹下手動裝配的過程:
- 首先定義用的 Bean
public class Cat{}
public class Animals {
public Animals(Cat cat){ }
}
- 在 xml 配置檔案中定義
<bean id="cat" class="com.demo.Cat" />
<!-- ①手動裝配,必須手動指定成員變量的依賴 Bean -->
<bean id="animals" class="com.demo.Animals" >
<constructor-arg name="cat" ref="cat"/>
</bean>
<!-- ②同樣意味這此時 autowire 屬性為 no ,同 ① 作用一樣 -->
<bean id="animals" class="com.demo.Animals" autowire="no">
<constructor-arg name="cat" ref="cat"/>
</bean>
- 建立容器驗證
public static void main(String [ ] args) {
String location = ...
ApplicationContext factory = new FileSystemXmlApplicationContext(location);
}
byName
根據屬性名自動裝配,預設會檢查整個容器中與屬性名稱相同的 Bean 辨別(包括 id,name,alias),并且該方式隻适用于 setter 注入。
- 定義 Bean
public class Cat{}
public class Animals {
private Cat cat;
//省略 sertter/getter...
}
- 在 xml 配置檔案中定義
<bean id="cat" class="com.demo.Cat" />
<!-- 與手動裝配相比,減少了配置的工作量 -->
<bean id="animals" class="com.demo.Animals" autowire="byName"/>
- 調用驗證
String location = ...
ApplicationContext factory = new FileSystemXmlApplicationContext(location);
Animals animals = (Animals) factory.getBean("animals");
System.out.println(animals.getCat());
需要注意的是,當容器中不存在辨別與屬性名比對的 bean 時,容器預設不會抛出異常,而是将屬性當作 null 對待,即在調用 get 方法時預設輸出 null。該特性同樣适用于所有的 setter 注入。
byType
根據屬性的類型自動裝配,預設會檢查整個容器與屬性類型相同的 Bean,該方式隻适用于 setter 注入。
同 byName 的自動裝配方式相似,該方式的配置僅僅是将 byName 替換成 byType 而已,如下所示:
但是該方式存在着一個巨大的隐患,我們知道 byName 是通過在容器中查找與屬性名稱相同的 Bean,由于 Spring 容器的限制,是不允許存在兩個辨別相同的 bean,是以通過該方式比對的結果預設隻有一個比對的 Bean。
但是 byType 不一樣,Spring 容器并沒有限制相同類型 Bean 的存在,隻要它們的辨別不一樣,即是合理的。下面來探究下這種情況:
- 定義 Bean
public class Cat{}
public class Animals {
private Cat cat;
//省略 sertter/getter...
}
- 在 xml 配置檔案中定義
<!-- ①存在多個類型相同,辨別不同的 Bean -->
<bean id="cat1" class="com.demo.Cat" />
<bean id="cat2" class="com.demo.Cat" />
<!-- ②即便不指定辨別,Spring 也自動生成不同的辨別,作用同 ① -->
<bean class="com.demo.Cat" />
<bean class="com.demo.Cat" />
<bean id="animals" class="com.demo.Animals" autowire="byType"/>
- 建立容器驗證
此時會抛出如下異常資訊:
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type...
這是不是意味着在使用 byType 自動裝配時,容器中就不能存在相同類型的 Bean 呢,答案當然是否定的,Spring 通過引入競選機制來解決這一問題。
1.primary
當一個 Bean 将 primary 辨別為 true,就表示自己是主要的的 Bean,該值預設為 flase。當存在多個相同類型的 Bean 時,自動裝配時會優先選擇它。
<!-- 正确 -->
<bean class="com.demo.Cat" primary="true" />
<bean class="com.demo.Cat" />
<!-- 錯誤 -->
<bean class="com.demo.Cat" primary="false" />
<bean class="com.demo.Cat" />
<!-- 錯誤 -->
<bean class="com.demo.Cat" primary="true" />
<bean class="com.demo.Cat" primary="true" />
2.autowire-candidate
與 primary 意思相同,當一個 Bean 将 autowire-candidate 辨別為 false,就表示自己不再是候選的的 Bean,而是主要的 Bean ,該值預設為 true,defalut。當存在多個相同類型的 Bean 時,自動裝配時會優先選擇該屬性為 false 的 Bean。
<!-- 正确 -->
<bean class="com.demo.Cat" autowire-candidate="false" />
<bean class="com.demo.Cat" />
<!-- 錯誤 -->
<bean class="com.demo.Cat" autowire-candidate="true" />
<bean class="com.demo.Cat" />
<!-- 錯誤 -->
<bean class="com.demo.Cat" autowire-candidate="default" />
<bean class="com.demo.Cat" />
<!-- 錯誤 -->
<bean class="com.demo.Cat" autowire-candidate="ture" />
<bean class="com.demo.Cat" autowire-candidate="default"/>
constructor
與 byType 相似,同樣是根據類型自動裝配,不同的是這裡比對的是構造參數的類型,主要用于 constructor(構造) 注入。
- 定義 Bean
public class Cat{}
public class Animals {
public Animals(Cat cat){ }
}
- 在 xml 配置檔案中定義
<bean class="com.controller.Cat" />
<bean id="animals" class="com.demo.Animals" autowire="constructor"/>
同樣該方式也存在相同類型 Bean 的隐患,解決方法與 byType 一緻,通過 primary、autowire-candidate 。
需要注意的是,與 byName 、byType 不同的是,該方式采用的構造注入,而不是 setter 注入。若 Bean 中沒有定義無參構造函數時,若在自動裝配時找不到比對的 Bean,則會抛出異常。而不會像 byName 、byType 把它當作 null 處理。
default
與 bean 的父标簽 beans 的 default-autowire 屬性有關,同 autowire 一緻,該屬性也有 no、default、byType、byName、constructor 這幾個值。
假設 beans 的 default-autowire 為 byType,則表示 bean 标簽中 autowire 為 default 都預設采用 byType 的注入方式。
具體配置形式如下:
<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
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd"
default-autowire="byType">
<bean class="com.controller.Cat" />
<!-- 此時采用 byType 的自動裝配方式 -->
<bean id="animals" class="com.demo.Animals" autowire="default"/>
</beans>
autodetect
判斷 Bean 的構造方法是否存在構造參數,若有則采用 constructor 自動裝配,否則采用 byType 自動裝配。
Spring 3.0 以後該方式已被抛棄,這裡就不再探究。若想要配置該注入方式,需要要把3.0的 xsd 替換為 2.5 的 xsd,否則會報錯。