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

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 15:56   1447   0

  我们已经看到如何使用自动装配让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类型来指定限定符,自定义的注解也更为类型安全。

转载于:https://www.cnblogs.com/TvvT-kevin/p/10004502.html

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP