一、前言

本文承接上一节:Spring_总结_04_高级配置(二)之条件注解@Conditional

我们前面装配bean时,在Spring容器中,都是只有一个bean能匹配所需的结果。

如果有多个bean能匹配结果的话,Spring就将无法做出选择,这就是自动装配的歧义性。

这一节我们将解决自动装配的歧义性

二、歧义实例

1.实体类

如下,有三个类都继承自Dessert

@Component
public class Cake implements Dessert {...} @Component
public class Cookies implements Dessert {...} @Component
public class IceCream implements Dessert {...}

2.注入bean

@Autowired
public void setDessert(Dessert dessert){
this.dessert = dessert;
}

3.异常

Spring有选择困难症,当Spring尝试自动装配 setDessert() 中的 Dessert 参数时,发现有三个选择,这时它会抛出一个NoUniqueBeanDefinitionException异常,来表示自己无从选择。

可用 @Primary 和 @Qualifier 来解决歧义问题。

三、@Primary

在声明Bean的时候,通过将其中一个可选的bean设置为首选(primary)Bean,能够避免自动装配的歧义性。

被@Primary注解的bean即可首选Bean。

1.配置首选Bean

配置首选Bean有如下两种方式:

(1)在组件类中配合@Component使用

@Component
@Primary
public class IceCream implements Dessert {...}

(2)在配置类中配合@Bean使用

@Bean
@Primary
public Dessert iceCream(){
return new IceCream();
}

2.注入bean

注入bean时,Spring会找到三个可选bean,其中一个是首选bean,因此会选择首选bean进行注入。

@Autowired
public void setDessert(Dessert dessert){
this.dessert = dessert;
}

注意:Spring 有选择困难症,若配置了两个及以上的首选Bean,则Spring有无从选择了。

四、@Qualifier

Spring 的限定符能够将bean限定到唯一一个满足要求的bean.

1. 基于ID的限定符

为@Qualifier注解所设置的参数就是想要注入的bean的 ID

@Autowired
@Qualifier("iceCream") //在注入的时候,指定注入的bean为 iceCream
public void setDessert(Dessert dessert){
this.dessert = dessert;
}

2. 面向特性的限定符

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

可在声明Bean或配置Bean时,使用@Qualifier注解设置限定符。

2.1 设置限定符

(1)在声明Bean时,设置限定符

@Component
@Qualifier("cold") //设置限定符为 cold
public class IceCream implements Dessert {...}

(2)在配置Bean时,设置限定符

@Bean
@Qualifier("cold") //设置限定符为 cold
public Dessert iceCream(){
return new IceCream();
}

2.2 使用限定符

@Autowired
@Qualifier("cold") //注入限定符为 cold 的bean
public void setDessert(Dessert dessert){
this.dessert = dessert;
}

3 自定义限定符注解

有时,我们想为bean设置多个限定符,如下:

@Component
@Qualifier("cold") //设置限定符为 cold
@Qualifier("creamy") //设置限定符为 creamy
public class Popsicle implements Dessert {...}

然而,Java不允许在同一个条目上重复出现相同类型的多个注解

为了解决这个问题,我们可以创建自定义的限定符注解。

(1)自定限定符注解

@Cold

@Target({
ElementType.TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Cold{ }

@Creamy

@Target({
ElementType.TYPE,
ElementType.CONSTRUCTOR,
ElementType.FIELD,
ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface Creamy{ }

(2)为bean设置多个限定符

@Component
@Cold
@Creamy
public class IceCream implements Dessert {...}

(3)注入bean时,使用多个限定符来限定

@Autowired
@Cold
@Creamy
public void setDessert(Dessert dessert){
this.dessert = dessert;
}

Spring_总结_04_高级配置(三)_处理歧义的更多相关文章

  1. Spring_总结_04_高级配置(二)_条件注解@Conditional

    一.前言 本文承接上一节:Spring_总结_04_高级配置(一)之Profile 在上一节,我们了解到 Profile 为不同环境下使用不同的配置提供了支持,那么Profile到底是如何实现的呢?其 ...

  2. Spring_总结_04_高级配置(五)_运行时注入值

    一.前言 本文承接上一节:Spring_总结_04_高级配置(四)_bean的作用域 当讨论依赖注入的时候,我们通常所讨论的是将一个bean引用注入到另一个bean的属性或者构造参数中.它通常指的是将 ...

  3. Spring_总结_04_高级配置(四)_bean的作用域

    一.前言 本文承接上一节:Spring_总结_04_高级配置(三)之处理歧义 1.单例bean Spring应用上下文中所有的bean默认都是单例的.也就是说,不管一个bean被注入到其他bean多少 ...

  4. Spring_总结_04_高级配置(六)_Bean的初始化和销毁

    一.前言 本文承接上一节:Spring_总结_04_高级配置(五)_运行时注入值

  5. Spring_总结_04_高级配置(一)_Profile

    一.前言 本文承接上一节:Spring_总结_03_装配Bean(四)之导入与混合配置 这一节,来总结一下profile. 我们在开发软件时,通常会进行跨环境部署.而在跨环境部署时,经常会遇到某些环境 ...

  6. Spring_总结_03_装配Bean(四)_导入与混合配置

    一.前言 本文承接上一节:Spring_总结_03_装配Bean(三)之XML配置 在典型的Spring应用中,我们可能会同时使用自动化和显示配置.同时,可能在某些场景下我们需要混合使用JavaCon ...

  7. [转]JEXUS的高级配置

    转自:http://www.cnblogs.com/xiaodiejinghong/archive/2013/04/14/3019660.html 前一回合,我们对服务器软件Jexus作了简单的介绍, ...

  8. Cisco ASA 高级配置

    Cisco ASA 高级配置 一.防范IP分片攻击 1.Ip分片的原理: 2.Ip分片的安全问题: 3.防范Ip分片. 这三个问题在之前已经详细介绍过了,在此就不多介绍了.详细介绍请查看上一篇文章:I ...

  9. Stm32高级定时器(三)

    Stm32高级定时器(三) 1 互补输出和死区插入 1.1 死区:某个处于相对无效状态的时间或空间 本来OCX信号与OCXREF时序同相同步,OCXN信号与OCXREF时序反相同步.但为了安全考虑,以 ...

随机推荐

  1. Unity3D游戏开发从零单排(六) - 人物运动及攻击连击

    提要 今天要实现的是一个简单人物控制器. 包括用w,a,s,d来控制人物上下左右跑动,鼠标左击发出连招,都是基于老的lagacy的动画.尽管unity3d自带有charactorcontroller, ...

  2. studio显示Surface: getSlotFromBufferLocked: unknown buffer: 0xa2a58be0

    根据查询外网资料来看,出现这个错误的原因大致是换个模拟器或者物理机就可以了. 因为我使用的是安卓6.0,貌似都会出现这类的问题. 但是不影响程序运行.

  3. numpy利用数组进行数据处理

    将条件逻辑表述为数组运算 numpy.where()是一个三目运算的表达式 In [34]: xarr = np.array([1.1,1.2,1.3,1.4,1.5]) In [35]: yarr ...

  4. C#类型基础(1)

    1.“运行时”要求每个类型最终都从 System.Object 类型派生.Object提供了Equals,GetHashCode,ToString,GetType公共方法,并提供MemberwiseC ...

  5. smarty模板及其应用

    Smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一.它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离. ...

  6. c# 泛型(Generic)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 泛型 { ...

  7. GZDBHelper

    NuGet:GZDBHelper 初始化: public class APIBase : ApiController { protected GZDBHelper.IDatabase db; publ ...

  8. 写给后端程序员的HTTP缓存原理介绍--怎样决定一个资源的Cache-Control策略呢

    通过Internet获取资源既缓慢,成本又高.为此,Http协议里包含了控制缓存的部分,以使Http客户端可以缓存和重用以前获 取的资源,从而优化性能,提升体验.虽然Http中关于缓存控制的部分,随着 ...

  9. 【P1947】笨笨当粉刷匠(DP+前缀和)

    这个题乍一看觉得挺简单的,事实上却完全不是.首先,这个题看上去无脑直接刷就可以然而因为刷的次数远远大于木板的个数所以不行,然后开始考虑DP,自己一开始是这么想的,如果用f[t][i][j]表示刷t次时 ...

  10. java基础(6)-集合类2

    泛型 泛型:是一种把类型明确的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型,参数化类型,把类型当做参数一样的传递 好处: 1)把运行时期的问题提前到了编译器期间 2)避免了强制类型转换 3 ...