我们已经看到如何使用自动装配让Spring完全负责将bean引用注入到构造参数和属性中。自动装配能够提供很大的帮助。不过,spring容器中仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,Spring此时别无他法,只好宣告失败并抛出异常。更精确地讲,Spring会抛出NoUniqueBeanDefinitionException。
当确实发生歧义性时,Spring提供了多种可选方案来解决这样的问题。你可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。
例子:
需要注入的bean:
在本例中,Dessert是一个接口,并且有三个类实现了这个接口,分别为Cake、Cookies和IceCream:
这三个实现均使用了@Component注解,在组件扫描的时候,能够发现它们并将其创建为Spring应用上下文里面的bean。然后,当Spring试图自动装配setDessert()中的Dessert参数时,它并没有唯一、无歧义的可选值。
Spring提供了多种可选方案来解决这样的问题。你可以将可选bean中的某一个设为首选(primary)的bean,或者使用限定符(qualifier)来帮助Spring将可选的bean的范围缩小到只有一个bean。
1、隐式(@Component)
2、显式(@Bean)
3、xml模式:
在声明bean的时候,通过将其中一个可选的bean设置为首选(primary)bean能够避免自动装配时的歧义性。当遇到歧义性的时候,Spring将会使用首选的bean,而不是其他可选的bean。实际上,你所声明就是“最喜欢”的bean。
如果有两个继承相同接口的类同时设置primary,则仍然会有歧义,因此引入Qualifier。Qualifier注解是使用限定符的主要方式,它可以与@AutoWired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。
例如,我们想要确保要将IceCream注入到setDessert()之中:
为@Qualifier注解所设置的参数就是想要注入的bean的ID。所有使用@Component注解声明的类都会创建为bean,并且bean的ID为首字母变为小写的类名,并且如果没有指定其他的限定符的话,所有的bean都会给定一个默认的限定符,这个限定符与bean的ID相同。因此,@Qualifier("iceCream")指向的是组件扫描时所创建的bean,并且这个bean是IceCream类的实例。
基于默认的bean ID作为限定符是非常简单的,但这有可能会引入一些问题。如果你重构了IceCream类,将其重命名为Gelato的话,那此时会发生什么情况呢?如果这样的话,bean的ID和默认的限定符会变为gelato,这就无法匹配setDessert()方法中的限定符。自动装配会失败。
为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。在bean声明上添加@Qualifier注解。
在这种情况下,cold限定符分配给了IceCreambean。因为它没有耦合类名,因此你可以随意重构IceCream的类名,而不必担心会破坏自动装配。在注入的地方,只要引用cold限定符就可以了:
在显式模式中:
错误示范:多个bean都具备相同特性的话,这种做法也会出现问题。可能想到的解决方案就是在注入点和bean定义的地方同时再添加另外一个@Qualifier注解
——————————————————————————
可是,如果有另外一个bean也同样使用了cold限定符呢,还是会出现歧义,而java不允许同一个条目上重复出现相同类型的多个注解,否则编译器会报错,所以我们需要创建自定义的限定符注解,借助这样的注解来表达bean所希望限定的特性。
当你不想用@Qualifier注解的时候,可以类似地创建@Soft、@Crispy和@Fruity。通过在定义时添加@Qualifier注解,它们就具有了@Qualifier注解的特性。它们本身实际上就成为了限定符注解。
@Qualifier("cold")被代替:
@Qualifier("creamy")被代替:
使用例子:
注解声明bean:
IceCream类可以添加@Cold和@Creamy注解:
Popsicle类可以添加@Cold和@Fruity注解:
注入bean:
通过声明自定义的限定符注解,我们可以同时使用多个限定符,不会再有Java编译器的限制或错误。与此同时,相对于使用原始的@Qualifier并借助String类型来指定限定符,自定义的注解也更为类型安全。
spring学习总结——高级装配学习一(处理自动装配的歧义性)
原文:https://www.cnblogs.com/TvvT-kevin/p/10004502.html