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. 我对数据库事务的理解(MYSQL中)

    -- 设置数据库事务为手动的提交SET @@AUTOCOMMIT = 0;-- 查看是否被修改SELECT @@autocommit;-- 查看当前的编码格式SELECT @@character_se ...

  2. Java程序设计学习笔记(五) — 多线程

    时间:2016-4-15 09:56 --多线程(还有多核编程)     1.进程         进程是一个正在执行中的程序.         每一个进程执行都有一个执行顺序,该顺序是一个执行路径, ...

  3. python操作图片

    时间:2018-11-30 记录:byzqy 标题:python实现图片操作 地址:https://blog.csdn.net/baidu_34045013/article/details/79187 ...

  4. 字符型:char

    字符型:char 字符变量的定义和输出 字符变量用于存储一个单一字符,在C语言中用char表示,其中每个字符变量都会占用1个字节.在给字符型变量赋值时,需要用一对因为半角格式的单引号('   ')把字 ...

  5. 图解最长回文子串「Manacher 算法」,基础思路感性上的解析

    问题描述: 给你一个字符串 s,找到 s 中最长的回文子串. 链接:https://leetcode-cn.com/problems/longest-palindromic-substring 「Ma ...

  6. vue 微信二维码扫码登录,附加 自定义样式

    大概流程:   先安装 微信 的登录, 然后 局部引入,局部注册,方法调用,存 token,跳转路由 npm 安装 npm install vue-wxlogin --save-dev 微信安装 微信 ...

  7. vue element-ui 组件上传图片 以及对 图片的 宽高 和 大小 格式等 做出限制

    vue  文件: 自行引用 elemen-ui    <el-upload                         action=" 让后端给你上传地址 "      ...

  8. Linux下chkconfig

    1.chkconfig命令用于检查,设置系统的各种服务! 2.chkconfig语法 chkconfig [--add] [--del] [--list] [系统服务] 或 chkconfig [-- ...

  9. js判断是在移动端还是在pc端

    function chatQQ3(){ if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) { //移动端打开 ...

  10. 添加class和删除class以及判断是否含有class

      addClass(document.body, 'showRightPanel') removeClass(document.body, 'showRightPanel') /**  * Add  ...