您的位置:首页 > 其它

高级装配 —— 如何处理自动装配的歧义性?

2017-07-28 15:21 375 查看
Q:自动装配时,什么情况下会产生歧义性?歧义性会导致什么?怎么处理?

A:如果不仅有一个 bean 能够匹配结果的话,就会出现歧义性。

它会阻碍 Spring 自动装配属性、构造器参数或方法参数,并抛出 NoUniqueBeanDefinitionException 异常。实际中,歧义性还是比较罕见的。

当出现歧义性的时候,Spring 提供了多种可选方案来解决:你可以将可选的 bean 中的某一个设为首选(primary)的 bean ; 或者使用限定符(qualifier)来帮助 Spring 将可选的 bean 的范围缩小到只有一个 bean

出现歧义性的代码:

// 自动装配 Dessert 参数时,并没有唯一、无歧义的可选值。
@Autowired
public void setDessert(Dessert dessert){
this.dessert = dessert;
}


@Component
public class Cake implements Dessert { }

@Component
public class Cookies implements Dessert { }

@Component
public class IceCream implements Dessert { }


Q:如何标示首选的 bean?

A:如下代码所示:

/**
* ①、@Primary 能够与 @Component 组合用在组件扫描的 bean 上。
*/
@
4000
Component
@Primary
public class IceCream implements Dessert { }

/**
* ②、也可以与 @Bean 组合用在 Java 配置的 bean 声明中。
*/
@Bean
@Primary
public Dessert iceCream(){
return new iceCream();
}

<!-- ③、XML 配置中,实现同样的功能 -->
<bean id="iceCream" class="com.desserteater.IceCream" primary="true"/>


注意:如果你标示了两个或更多的首选 bean,那么它就无法正常工作了。

就解决歧义性问题而言,限定符更为强大。

设置首选bean的局限性:无法将可选方案的范围限定到唯一一个无歧义性的选项中。他只能标识一个优先的可选方案,当首选 bean 的数量超过一个时,无法进一步缩小可选范围。

Q:如何限定自动配置的 bean?

Spring 的限定符能够在所有可选的 bean 上进行缩小范围的操作,最终能够达到只有一个 bean 满足所规定的限制条件。

A:@Qualifier 注解使用限定符的主要方式。它可以与 @Autowired@Inject 协同使用,在注入的时候指定想要注入进去的是哪个 bean。代码如下:

/**
* 想要确保要将 IceCream 注入到 setDessert()之中。
* 这是使用限定符的最简单的例子。
* @param dessert
*/
@Autowired
// 参数就是想要注入的 bean 的ID。
// @Qualifier("iceCream") 所引用的 bean 要具有 String 类型的"iceCream"作为限定符,
// 所有的 bean 都会给定一个默认的限定符,这个限定符与 bean 的 ID 相同。
@Qualifier("iceCream")
public void setDessert(Dessert dessert){
this.dessert = dessert;
}


此时,方法上所指定的限定符与要注入的 bean 的名称是紧耦合的。

Q:如何创建自定义的限定符?

我们可以为 bean 设置自己的限定符,而不是依赖于将 bean ID 作为限定符。

A:在 bean 声明上添加 @Qualifier 注解。

/**
* cold 限定符分配给了 IceCream bean
* 此时,没有耦合类名,可以随意重构 IceCream 的类名,而不用担心会破坏自动装配。
*/
@Component
@Qualifier("cole")
public class IceCream implements Dessert {
}

@Autowired
// 注入的地方,引用 code 限定符即可。
@Qualifier("cole")
public void setDessert(Dessert dessert){
this.dessert = dessert;
}


// 当通过 Java 配置显示定义 bean 时,也可以与 @Bean 注解一起使用
@Bean
@Qualifier("cold")
public Dessert iceCream(){
return new IceCream();
}


为了能够使用多个限定符,我们需要自定义限定符注解。

Q:如何使用自定义的限定符注解?

A:

/**
* 因为 Java 不允许在同一条目上重复出现相同类型的多个注解
* 所以使用自定义的 @Cold 来替换 @Qualifier("cold")
* 它们具有了 @Qualifier 注解的特性。本身实际上就成为了限定符注解。
*/
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold {
}


// 使用必要的限定符注解进行任意组合,从而将可选范围缩小到只有一个 bean 满足需求。
@Autowired
@Cold
@Creamy
public void setDessert(Dessert dessert){
this.dessert = dessert;
}


上一篇:高级装配 —— 条件化的 bean

下一篇:高级装配 —— 如何在不同的作用域中声明 bean?
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: