Spring自动装配歧义性笔记

如果系统中存在两个都实现了同一接口的类,Spring在进行@Autowired自动装配的时候,会选择哪一个?如下:

// 一下两个类均被标记为bean
@Component
public class CD implements Playable {
@Override
public void play() {
System.out.println("CD is playing...");
}
}
@Component
public class Video implements Playable {
@Override
public void play() {
System.out.println("Video is playing...");
}
} //配置类仅打开自动扫描
@Configuration
@ComponentScan(basePackages = "zhen"
public class MyConfig {
} //测试类
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = MyConfig.class)
public class MyConfigTest {
@Autowired
Playable playable;
@Test
public void checkNULL() {
Assert.assertNotNull(playable);
}
}

此时再次运行测试类会发现,FAILD并且报错:

Unsatisfied dependency expressed through field 'playable'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'zhen.Playable' available: expected single matching bean but found 2: CD,video // 找到了两个都bean都能匹配

自动装配歧义性问题

上面的异常就是出现了歧义性。Spring为我们扫描了我们代码中的bean(这个部分是没有问题的),但是,在自动装配的过程中却由于歧义性而报错,并且,造成这样的歧义性还有由于Autowired这个注解仅仅按照类型进行装配——上面的CD与Video都实现了Playable接口,Autowired注解仅告诉Spring在测试类中的playable接受一个Playable类型的对象但是这里有两个bean:CD、video都是Playable类型的,所以Spring不知道。

为了解决这个问题,我们需要通过一定的手段来限定:

声明首选的bean
限定自动转配的bean

声明首选的bean

根据名字我们很容易理解,就是声明在有歧义性情况下,Spring到底选择哪一个bean来装配。方式就是在bean组件下添加@Primary注解,例如在原先的CD的@Component下加上首选注解,再次运行测试代码,PASS。但是,这种方式通常只在同类型bean较少的或者是系统简单的情况使用,而且还存在一个情况:假如目前有两位开发人员,在各自的环境编写bean,他们都希望自己的bean是Primary的,都加该注解,实际上还是会报错,因为系统现在同样有两个Primary bean,Spring还是不能判断选择哪一个bean注入。

限定自动装配的bean——@Qualifier注解

首先,我们可以通过在@Component中加入字符串来更明确的指定bean id而不是使用Spring的默认bean id策略。就像如下:

@Component("myCD")
public class CD implements Playable {
// ...
}
@Component("myVideo")
public class Video implements Playable {
// ...
}

当这样指定以后,我们在自动转配的地方,使用@Qualifier("指定id")来限定我们要注入的确定的bean:

  ...
@Autowired
@Qualifier("myCD")
Playable playable;
...

再次运行不会报错。

关于@Qualifier,最佳的情形应该是来标记bean特性。但是,如果多个bean都有相同的特性,都是用了相同的标记的@Qualifier注解,那么同样又会出现歧义性问题。所以我们又要添加新的@Qualifier注解来进一步限定,这样做没有问题,但是Java语法规定,不允许在同一条目上重复出现相同类型的多个注解。你不能这么做:

// 编译器会报错
@Qualifier("myCD")
@Qaulifier("JayChou")
public class CD implements Playable {
...
}

为了结局这样的问题,我们可以创建自己的注解:

@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.METHOD}) //字段注解
@Retention(RetentionPolicy.RUNTIME) //在运行期保留注解信息
@Qualifier // 需要使用@Qualifier注解来限定
public @interface MyCD {
}
@Target({ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier
public @interface JayChou {
}

如此定义了注解以后,我们就可以在原先的@Component下如下定义:

@Component
@MyCD
@JayChou
public class CD implements Playable {
...
}

并且在测试类下如下声明:

    @Autowired
@MyCD
@JayChou
Playable playable;

测试通过!

Spring自动装配歧义性笔记的更多相关文章

  1. Spring自动装配(二)

    为什么Spring要支持Autowire(自动装配) 先写几个类,首先定义一个Animal接口表示动物: 1 public interface Animal { 2 3 public void eat ...

  2. Spring 自动装配 Bean

    Spring3系列8- Spring 自动装配 Bean 1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiri ...

  3. spring 自动装配 default-autowire="byName/byType"

    <PRE class=html name="code">spring 自动装配 default-autowire="byName/byType"   ...

  4. Spring自动装配Bean详解

    1.      Auto-Wiring ‘no’ 2.      Auto-Wiring ‘byName’ 3.      Auto-Wiring ‘byType 4.      Auto-Wirin ...

  5. Spring自动装配----注解装配----Spring自带的@Autowired注解

    Spring自动装配----注解装配----Spring自带的@Autowired注解 父类 package cn.ychx; public interface Person { public voi ...

  6. Spring系列七:Spring 自动装配

    相思相见知何日?此时此夜难为情. 概述 在Spring框架中,在配置文件中声明bean的依赖关系是一个很好的做法,因为Spring容器能够自动装配协作bean之间的关系.这称为spring自动装配. ...

  7. 吴裕雄--天生自然JAVA SPRING框架开发学习笔记:Spring自动装配Bean

    除了使用 XML 和 Annotation 的方式装配 Bean 以外,还有一种常用的装配方式——自动装配.自动装配就是指 Spring 容器可以自动装配(autowire)相互协作的 Bean 之间 ...

  8. spring自动装配和通过java实现装配

    1.组建扫描 在类上添加注解@Component注解可以实现组建扫描 @Component public class A{ ... } 2.自动装配 通过在属性上或者方法上添加@Autowired注解 ...

  9. 【spring 注解驱动开发】spring自动装配

    尚学堂spring 注解驱动开发学习笔记之 - 自动装配 自动装配 1.自动装配-@Autowired&@Qualifier&@Primary 2.自动装配-@Resource& ...

随机推荐

  1. docker 安装Hive

    转自:https://www.cnblogs.com/upupfeng/p/13452385.html#%E9%83%A8%E7%BD%B2hive 使用docker快速搭建hive环境   记录一下 ...

  2. spring boot应用常用配置

    pom.xml <!--自动打包--> <plugin> <groupId>org.springframework.boot</groupId> < ...

  3. 微信小程序 转盘抽奖 倒计时 整点

    xml: <view id="luckdraw_box"> <view id="luckdraw_back"> <image st ...

  4. C# - 习题07_计算1分2分5分硬币各有多少枚

    时间:2017-09-08 整理:byzqy 题目:现在有1分.2分.5分硬币共100个,总金额为2.46元,请用程序计算出1分.2分.5分各有多少枚,有多少种算法? 这是最近面试遇到的一个题目,刚开 ...

  5. jquery mobile常用的data-role类型

    data-role参数表: page        页面容器,其内部的mobile元素将会继承这个容器上所设置的属性 header     页面标题容器,这个容器内部可以包含文字.返回按钮.功能按钮等 ...

  6. Linux 单实例oracle安装步骤

    一.查看逻辑盘大小,执行 lsblk 二.查看硬盘及分区信息 ,执行 fdisk -l 三.将物理硬盘分区初始化为物理卷,以便LVM使用 ,创建pv pvcreate /dev/sdb 四.查看物理卷 ...

  7. Linux centos7 nginx 的安装

    2021-08-18 1. 环境 # 操作系统[root@test007 /]# uname -aLinux test007 3.10.0-862.el7.x86_64 #1 SMP Fri Apr ...

  8. sublime text build system automatic ctrl/cmd+B自动选择 python2 或 python3

    背景 我同时安装了 python2 和 python3 时,python 指向 python2,python3 才是 python3 默认情况下,在 Sublime 内 Ctrl/Cmd + B 运行 ...

  9. javaScript知识储备

    javaScript知识储备 组成 ECMAScript(核心) 提供语法.变量等,遵循ECMA-262标准 DOM(文档对象模型) 提供操作HTML标签的API,遵循W3C规范 BOM(浏览器对象模 ...

  10. shell传参和变量赋值

    1.变量赋值方式 (1)方式1--直接赋值(=) (2)方式2--read交互式赋值 (3)方式3--脚本传参赋值 2.read read -p "请输入你的名字和年龄:" nam ...