在默認情況下使用 @Autowired
註釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出BeanCreationException
異常,並指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:
<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-2.5.xsd ">
<bean class="org.springframework.beans.factory.annotation.
AutowiredAnnotationBeanPostProcessor"/>
<bean id="boss" class="com.baobaotao.Boss"/>
<!-- 將 office Bean 註釋掉 -->
<!-- <bean id="office" class="com.baobaotao.Office">
<property name="officeNo" value="001"/>
</bean>-->
<bean id="car" class="com.baobaotao.Car" scope="singleton">
<property name="brand" value=" 紅旗 CA72"/>
<property name="price" value="2000"/>
</bean>
</beans>
office
Bean 被註釋掉了,所以 Spring 容器中將沒有類型爲 Office
的 Bean 了,而 Boss 的office
屬性標註了@Autowired
,當啓動 Spring 容器時,異常就產生了。
當不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用 @Autowired(required = false)
,這等於告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:
清單 11. 使用 @Autowired(required = false)
package com.baobaotao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
public class Boss {
private Car car;
private Office office;
@Autowired
public void setCar(Car car) {
this.car = car;
}
@Autowired(required = false)
public void setOffice(Office office) {
this.office = office;
}
…
}
@Autowired
的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如爲了快速啓動 Spring 容器,僅引入一些模塊的 Spring 配置文件),所以@Autowired(required = false)
會很少用到。
和找不到一個類型匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 Bean,Spring 容器在啓動時也會拋出 BeanCreationException
異常。來看下面的例子:
清單 12. 在 beans.xml 中配置兩個 Office 類型的 Bean
<bean id="office" class="com.baobaotao.Office">
<property name="officeNo" value="001"/>
</bean>
<bean id="office2" class="com.baobaotao.Office">
<property name="officeNo" value="001"/>
</bean>
…
我們在 Spring 容器中配置了兩個類型爲 Office
類型的 Bean,當對 Boss 的 office
成員變量進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。
Spring 允許我們通過 @Qualifier
註釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:
清單 13. 使用 @Qualifier 註釋指定注入 Bean 的名稱
public void setOffice(@Qualifier("office")Office office) {
this.office = office;
}
@Qualifier("office")
中的 office
是 Bean 的名稱,所以 @Autowired
和@Qualifier
結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired
可以對成員變量、方法以及構造函數進行註釋,而@Qualifier
的標註對象是成員變量、方法入參、構造函數入參。正是由於註釋對象的不同,所以
Spring 不將 @Autowired
和@Qualifier
統一成一個註釋類。下面是對成員變量和構造函數入參進行註釋的代碼:
對成員變量進行註釋:
public class Boss {@Autowired
private Car car;
@Autowired
@Qualifier("office")
private Office office;
…
}
對構造函數入參進行註釋:
清單 15. 對構造函數變量使用 @Qualifier 註釋
private Car car;
private Office office;
@Autowired
public Boss(Car car , @Qualifier("office")Office office){
this.car = car;
this.office = office ;
}
}
@Qualifier
只能和 @Autowired
結合使用,是對 @Autowired
有益的補充。一般來講,@Qualifier
對方法簽名中入參進行註釋會降低代碼的可讀性,而對成員變量註釋則相對好一些。