1.Spring 自动装配的歧义性
我们已经知道,利用自动装配可以减少显式配置的数量,为我们带来很大的方便。但是,如果不仅有一个 bean 能够匹配的话,Spring 就无法进行自动装配了。
举个例子,我们使用 @Autowired 注解标注了 setDessert() 方法:
1 2 3 4 | @Autowired public void setDessert(Dessert dessert) { this.dessert = dessert; } |
与此同时,我们有两个类实现了这个接口,一个叫做 Cake,另一个叫做 IceCream:
1 2 3 4 5 | @Component public class Cake implements Dessert {...} @Component public class IceCream implements Dessert {...} |
那么此时 Spring 究竟是应当注入 Cake 呢?还是注入 IceCream 呢?Spring 也无法判断,因此它会抛出一个 NoUniqueBeanDedinitionException 的异常。
2.如何解决自动装配的歧义性
Spring 提供了多种方法来解决这个问题,说明如下:
2.1.使用 @primary 注解:标示首选bean 是哪个
@Primary 注解的使用方式如下:
1 2 3 | @Component @Primary public class IceCream implements Dessert {...} |
@Primary 注解使得在有多个满足条件的 bean 同时存在是,提供一种优先的解决方案。
2.2.使用 @Qualifier 注解
@Qualifier 注解的使用方式如下:
1 2 3 4 5 | @Autowired @Quatifier("iceCream") public void serDessert(Dessert dessert) { this.dessert = dessert; } |
@Qualifier 注解中的 iceCream 为 IceCream 类名首字母变为小写的结果。
当然,你也可以像这样使用 @Qualifier 注解。
1 2 3 4 5 6 7 8 9 | @Component @Qualifier("cold") public class IceCream implements Dessert {...} @Bean @Qualifier("cold") public void setDessert(Dessert dessert) { this.dessert = dessert; } |
也可以使用xml配置的方式:<bean>元素有一个primary属性来指定首选的bean:
<bean id="iceCream" class="xxxx" primary="true">
上面的使用方式有利于解耦和代码重构。
2.3.自定义的注解
除此之外,我们还可以创建新的注解(如 @Cold)来代替 @Qualifier(“cold”):
1 2 3 4 | @Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE}) @Retention(RetentPolicy.Runtime) @Qualifier public @interface Cold { } |
一般情况下,这个接口放在 Cold.java 里。这样我们就可以直接使用注解 @Clod:
1 2 3 4 5 | @Bean @Cold public void setDessert(Dessert dessert) { this.dessert = dessert; } |
当然,我们也可以同时使用多个注解来缩减范围:
1 2 3 4 5 6 | @Bean @Cold @Creamy public void setDessert(Dessert dessert) { this.dessert = dessert; } |