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. servlet中servletContext的五大作用(三)

    1.    获取web的上下文路径 2.    获取全局的参数 3.    作为域对象使用 4.    请求转发 5.    读取web项目的资源文件 package day10.about_serv ...

  2. JDBC中级篇——批处理和PreparedStatement对有sql缓冲区的数据库的友好,测试

    注意:其中的JdbcUtil是我自定义的连接工具类:代码例子链接: package a_batch; import util.JdbcUtil; import java.sql.Connection; ...

  3. JAVA简单精确计算工具类

    1 public class ArithUtil { 2 3 // 默认除法运算精度 4 private static final int DEF_DIV_SCALE = 10; 5 6 privat ...

  4. Flink与Strom两个框架的对比分析

    一.Flink与Storm两个框架的对比 二.Flink 的特性 1.高吞吐.低延迟.高性能 2.支持带事件的窗口(window) 操作:time.count.session.data-driven ...

  5. 工作多年后再来聊聊IO

    IO模型 IO是Input/Output的缩写.Linix网络编程中有五种IO模型: blocking IO(阻塞IO) nonblocking IO(非阻塞IO) IO multiplexing(多 ...

  6. QT如何发布应用程序和图标

    1.程序图标 ①创建一个图标格式的文件,可以网上在线将普通的图形格式转成.ico 格式的图标文件 http://www.faviconico.org/ 这个网站可以在线转换png.jpg.gif文件为 ...

  7. k8s笔记0528-基于KUBERNETES构建企业容器云手动部署集群记录-4

    部署kubelet 1.二进制包准备 将软件包从linux-node1复制到linux-node2中去. [root@linux-node1 ~]# cd /usr/local/src/kuberne ...

  8. WAMP 2.5 无法访问局域网的解决方法

    打开Apache配置文件 httpd.conf  (该文件在wamp\bin\apache\apache2.4.9\conf) DocumentRoot "d:/wamp/www/" ...

  9. bat 使用ftp进行文件上传

    实例 @echo off rem 打开远程ftp echo open 172.16.137.23 > ftpconfig.txt rem 使用匿名用户登录 echo user anonymuou ...

  10. client-go实战之三:Clientset

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...