Spring自动转配的歧义

发生的场景

类结构图 :

 

Spring自动转配的歧义

 

当一个方法接收接口作为参数,而其中,这个接口有多个实现,自动注入报错

@Autowired
public void comeRoom(Human human){
   this.human = human;
}
@Component
public class Eisteddfod implements Human { ... }
@Component
public class Knight implements Human { ... }
@Component
public class Merchant implements Human { ... }

报错信息 :

Spring自动转配的歧义

 

第一种解决方式 : 设置首选bean

Java方式实现

@Component
@Primary
public class Knight implements Human {...}

XML方式实现

<bean id="knight"
     class="autoAmbiguity.bean.Knight"
     primary="true" />

缺点 : 在有两个首选的Dessert bean的时候,这就会带来了新的歧义性问题

 

第二种解决方式 : 设置限定符

@Autowired
@Qualifier("knight")
public void comeRoom(Human human){
   this.human = human;
}

@Qualifier注解所设置的参数限定符

你重构了IceCream类,将其重命名为Gelato的话,这就无法匹配comeRoom()方法中的限定符

缺点 : 方法上所指定的限定符与要注入的bean的名称是紧耦合的。对类名称的任意改动都会导致限定符失效

所有的bean都会给定一个默认的限定符,这个限定符与bean的ID相同

解决方案 : 为bean设置自己的限定符,而不是依赖于将bean ID作为限定符

@Component
@Qualifier("knight")
public class Knight implements Human {...}

 

使用自定义的限定符注解

Java不允许在同一个条目上重复出现相同类型的多个注解

[1]Java 8允许出现重复的注解,只要这个注解本身在定义的时候带有@Repeatable注解就可以。不过,Spring的@Qualifier注解并没有在定义时添加@Repeatable注解。

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
       ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Brave {
}

 

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD,
       ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Mercy {
   // 仁慈
}

 

设置类的多个限定符

@Component
@Brave
@Mercy
public class Knight implements Human { ... }

通过声明自定义的限定符注解,我们可以同时使用多个限定符,不会再有Java编译器的限制或错误

@Autowired
@Brave
@Mercy
public void comeRoom(Human human) {
   this.human = human;
}