处理自动装配的歧义性
自动装配能够提供很大的帮助,因为它会减少装配应用程序组件时所需要的显式配置的数量。不过,仅有一个bean匹配所需的结果时,自动装配才是有效的。如果不仅有一个bean能够匹配结果的话,这种歧义性会阻碍Spring自动装配属性、构造器参数或方法参数。Spring使用 自动装配(@Autowired )注入 bean,spring不懂该去选哪个就会报错。 如下例子:
目录结构
DiskInterface为接口,DiskImpl和DiskImpl1为它的实现
DiskImpl:
package interfaces;
import org.springframework.stereotype.Component;
@Component
public class DiskImpl implements DiskInterface {
public void play() {
System.out.println(" i am ds");
}
}
DiskImpl1:
package interfaces;
import org.springframework.stereotype.Component;
@Component
public class DiskImpl1 implements DiskInterface {
public void play() {
System.out.println(" i am ds1");
}
}
CDConfig:
package config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
//默认扫描config配置类下的bean,如果不指定包名,interfaces包下就没有bean生成
@ComponentScan(basePackages={"config","interfaces"})
public class CDConfig {
}
ConstuctBean:
package interfaces;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class ConstuctBean {
@Autowired
private DiskInterface di;
public ConstuctBean(DiskInterface di){
this.di=di;
}
//使用自动注入需要默认的无参构造器 否则spring会报错
public ConstuctBean(){
}
public void show(){
di.play();
}
}
CDplayer测试:
package interfaces;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import config.CDConfig;
public class CDPlayer {
public static void main(String[] args) {
//JavaConfig上下文,加载配置文件
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(CDConfig.class);
ConstuctBean cb = (ConstuctBean) ac.getBean("constuctBean");
cb.show();
}
}
报错:[interfaces.DiskInterface] is defined: expected single matching bean but found 2: diskImpl,diskImpl1, 说是期待一个匹配的bean却出现了两个,劳资
不懂怎么选了,spring直接报错罢工。
解决方法:
1、标示首选的bean ,
Spring将会使用首选的bean,而不是其他可选的bean。实际上,你所声明就是“最喜欢”的bean。假设冰激凌就是你最喜欢的甜点。在Spring中,可以通过@Primary
来表达最喜欢的方案。@Primary
能够与@Component
组合用在组件扫描的bean上,也可以与@Bean
组合用在Java配置的bean声明中
2、在自动注入(@Autowired)的地方加入 @Qualifier("diskImpl"),即@Autowired @Qualifier("diskImpl") 两个注解一起使用,通过
名字指定具体的bean,这样就不会报错了,在这里我们的DiskImpl没有设定特定的bean名,所以默认bean Id为diskImpl。 如果想给DiskImpl指定特定名称也行@Component("dsk")(或者是@Component @Qualifier("dsk")这种方式设定名称比较麻烦,前面那种比较简便),那么在ConstuctBean中就@Autowired @Qualifier("dsk") 可以去到具体的注入的bean实例了。 @Autowired @Qualifier("dsk") 其实等价于@Resource("dsk")推荐使用这种,这种不是spring框架的 是java框架的没有跟spring耦合,@Resource默认是按照bean名字是找到指定的bean对象,如果找不到则按照类型查找(即按照autowired方式)