当候选 Bean 数目不为 1 时的应对方法

在默认情况下使用 ​​@Autowired​​ 凝视进行自己主动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个。

当找不到一个匹配的 Bean 时,Spring 容器将抛出​​BeanCreationException​​ 异常。并指出必须至少拥有一个匹配的 Bean。我们能够来做一个实验:


清单 10. 候选 Bean 数目为 0 时

<?xml version="1.0" encoding="UTF-8" ?
<?xml version="1.0" encoding="UTF-8" ?


因为 ​​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 的名称

@Autowired
public void setOffice(@Qualifier("office")Office office) {
this.office = office;
}


​@Qualifier("office")​​ 中的​​office​​ 是 Bean 的名称,所以​​@Autowired​​ 和​​@Qualifier​​ 结合使用时,自己主动注入的策略就从 byType 转变成 byName 了。​ ​@Autowired​​ 能够对成员变量、方法以及构造函数进行凝视,而​​@Qualifier​​ 的标注对象是成员变量、方法入參、构造函数入參。

正是因为凝视对象的不同,所以 Spring 不将​​@Autowired​​ 和​​@Qualifier​​ 统一成一个凝视类。以下是对成员变量和构造函数入參进行凝视的代码:

对成员变量进行凝视:


清单 14. 对成员变量使用 @Qualifier 凝视

public class Boss {
@Autowired
private Car car;

@Autowired
@Qualifier("office")
private Office office;

}


对构造函数入參进行凝视:


清单 15. 对构造函数变量使用 @Qualifier 凝视

public class Boss {
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​​ 对方法签名中入參进行凝视会减少代码的可读性,而对成员变量凝视则相对好一些。