处理自动装配的歧义性
仅有一个 bean 匹配所需的结果时,自动装配才是有效的。如果不仅有一个 bean 能够匹配结果的话,这种歧义性 Spring 自动装配。
例如下面案例
实体类
@Component
public class IceCream implements Dessert {
@Override
public void show() {
System.out.println("获得冰淇淋");
}
}
@Component
public class Cake implements Dessert {
@Override
public void show() {
System.out.println("获得蛋糕");
}
}
业务类
@Component
public class MyService {
private Dessert dessert;
public void show(){
dessert.show();
}
@Autowired
public void setDessert(Dessert dessert) {
this.dessert = dessert;
}
}
测试
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(com.lt.ltconfig.class);
MyService myService = (MyService) context.getBean("myService");
myService.show();
}
在这里,业务类根据接口匹配相应的 bean,但是继承了这个接口的 bean 有两个,Spring 不会帮我们选择,直接报错:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.lt.pojo.Dessert' available: expected single matching bean but found 2: cake,iceCream
此时,自动装配产生了歧义性。
要消除歧义性,Spring 提供了多种可选方案来解决这样的问题。可以将可选 bean 中的莫一个设为首选 (primary) 的 bean,或者使用限定符 (qualifier) 来帮助 Spring 将可选的 bean 的范围缩小到只有一个 bean。
1. 标识首选的 bean
通过将其中一个可选的 bean 设置为首选 (primary) bean 能够避免自动装配时的歧义性。当遇到歧义的时候,Spring 将会使用首选的 bean,而不是其他可选的 bean。当然,首选 bean 应该在一类 bean 中最多存在一个。设置首选 bean 的方法也很简单,在自动装配或者 java 配置中声明 @Primary 即可。xml 中将 bean 元素的 primary 属性设置为 true 即可。
2. 限定自动装配的 bean
2.1 使用限定符
@Qualifier 注解是使用限定符的主要方式,它可以与 @Autowired 和 @Inject 协同使用,在注入的时候指定想要注入进去的是哪个 bean。例如:
实体类
@Component
@Qualifier("iceCream")
public class IceCream implements Dessert {
@Override
public void show() {
System.out.println("获得冰淇淋");
}
}
业务类
@Component
public class MyService {
private Dessert dessert;
public void show(){
dessert.show();
}
@Autowired
@Qualifier("iceCream")
public void setDessert(Dessert dessert) {
this.dessert = dessert;
}
}
当通过 Java 配置显示定义 bean 的时候,@Qualifier 也可以与 @Bean 注解一起使用:
@Bean
@Qualifier("iceCream")
public Dessert iceCream(){
return new IceCream();
}
2.2 使用自定义的限定符注解
实体类
@Component
@Soft
public class Cake implements Dessert {
@Override
public void show() {
System.out.println("获得蛋糕");
}
}
业务类
@Autowired
@Soft
public void setDessert(Dessert dessert) {
this.dessert = dessert;
}
自定义注解
@Target({ElementType.CONSTRUCTOR,ElementType.FIELD,
ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Soft {
}
浙公网安备 33010602011771号