当通过接口的方式注入Bean时,如果有多个子类的bean存在时,具体哪个bean会被注入呢?系统中能否存在两个重名的bean呢?如果可以,那么怎么选择引入呢?如果不行的话又该怎么避免上面的问题呢?
I. 多实例Bean的选择
这个场景可以说是比较常见的,现在提倡面向接口编程嘛,当一个接口有多个实例时,怎么注入和引用就需要我们额外关注下了
基本使用姿势
首先定义一个接口和两个简单的实现类,并演示一下我们通常的用法
一个输出的接口定义如下
public interface IPrint {
void print(String msg);
}
对应给两个实现
@Component
public class ConsolePrint implements IPrint {
@Override
public void print(String msg) {
System.out.println("console print: " + msg);
}
}
@Slf4j
@Component
public class LogPrint implements IPrint {
@Override
public void print(String msg) {
log.info("log print: {}", msg);
}
}
下面就是我们一般的引用方式
@Autowired注解时,属性名即为默认的Bean名,如下面的logPrint就是获取beanName=logPrint的bean
@Resource(name=xxx) 直接指定Bean的name,来唯一选择匹配的bean
@Component
public class NormalPrintDemo {
@Resource(name = "consolePrint")
private IPrint consolePrint;
@Autowired
private IPrint logPrint;
@PostConstruct
public void init() {
consolePrint.print(" console print!!!");
logPrint.print(" log print!!!");
}
}
上面是两种常见的使用姿势,此外还可以借助@Primary注解来声明默认的注入bean
@Primary注解
这个注解就是为了解决当有多个bean满足注入条件时,有这个注解的实例被选中
根据上面的作用说明,很明显可以得知一点
@Primary注解的使用有唯一性要求:即对应上面的case,一个接口的子类中,只能有一个实现上有这个注解
假设将这个注解放在LogPrint上之后,如下
@Slf4j
@Component
@Primary
public class LogPrint implements IPrint {
@Override
public void print(String msg) {
log.info("log print: {}", msg);
}
}
结合上面的常用姿势,加上这个注解之后,我们的测试用例应该至少包含下面几个
@Resource 指定beanName的是否会被@Primary影响
前面的@Autowired注解 + 属性名的方式