spring学习总结——高级装配学习一(处理自动装配的歧义性)

Posted tvvt-kevin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring学习总结——高级装配学习一(处理自动装配的歧义性)相关的知识,希望对你有一定的参考价值。

  我们已经看到如何使用自动装配让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。

一、标示首选的bean(@Primary)

1、隐式(@Component)

  技术分享图片

2、显式(@Bean)

  技术分享图片

3、xml模式:

  技术分享图片

 

  在声明bean的时候,通过将其中一个可选的bean设置为首选(primary)bean能够避免自动装配时的歧义性。当遇到歧义性的时候,Spring将会使用首选的bean,而不是其他可选的bean。实际上,你所声明就是“最喜欢”的bean。

二、@Qualifier限定符

  如果有两个继承相同接口的类同时设置primary,则仍然会有歧义,因此引入Qualifier。Qualifier注解是使用限定符的主要方式,它可以与@AutoWired和@Inject协同使用,在注入的时候指定想要注入进去的是哪个bean。

1、基于默认的bean ID作为限定符

 

例如,我们想要确保要将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()方法中的限定符。自动装配会失败。

2、创建自定义的限定符

为bean设置自己的限定符,而不是依赖于将bean ID作为限定符。在bean声明上添加@Qualifier注解。

   技术分享图片

 

在这种情况下,cold限定符分配给了IceCreambean。因为它没有耦合类名,因此你可以随意重构IceCream的类名,而不必担心会破坏自动装配。在注入的地方,只要引用cold限定符就可以了:

  技术分享图片

 

在显式模式中:

  技术分享图片

 

3、使用自定义的限定符注解

错误示范:多个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学习总结——高级装配学习一(处理自动装配的歧义性)的主要内容,如果未能解决你的问题,请参考以下文章

spring学习总结——高级装配学习三(Bean的作用域)

Spring_总结_04_高级配置之处理歧义

spring学习总结——装配Bean学习三(xml装配bean)

Spring大略学习

Spring大略学习

Spring大略学习