@Autowired 被动注入形式有两种,一种是 bytype 另外一种是 byname,默认的方式是 bytype,Spring 会去容器中根据接口类型去寻找实现的 Bean,那么会有以下几种情况:
- 找不到任何一个 Bean
- 只有一个实现的 Bean
- 找到多个实现类
我们分别对看下这三种情况
找不到任何一个实现类
- 定义一个 ISkill 接口
public interface ISkill {
void r();
}
- controller 中注入该接口
@RestController
@RequestMapping("/v1/banner")
public class BannerController {
@Autowired
private ISkill iSkill;
@GetMapping("/test")
public String test() {
iSkill.r();
return "Hello China";
}
}
这时Idea会直接提示报错: Could not autowire. No beans of 'ISkill' type found.
只有一个实现类
- 定义一个实现类
@Component
public class Hero1 implements ISkill {
public Hero1() {
System.out.println("实例化Hero1对象");
}
@Override
public void r() {
System.out.println("Hero1......");
}
}
如果只有一个的情况下,会直接注入到容器中,不会有任何的影响。
有多个实现类
@Component
public class Hero1 implements ISkill {
public Hero1() {
System.out.println("实例化Hero1对象");
}
@Override
public void r() {
System.out.println("Hero1......");
}
}
@Component
public class Hero2 implements ISkill {
public Hero2() {
System.out.println("实例化Hero1对象");
}
@Override
public void r() {
System.out.println("Hero2......");
}
}
这个是如果我们在 Controller 中如果注入的类的名称不是任何一个实现类的名称,依然报错 Could not autowire. There is more than one bean of 'ISkill' type.
@RestController
public class BannerController {
@Autowired
private ISkill iSkill;
@GetMapping("/test")
public String test() {
iSkill.r();
return "Hello China";
}
}
但是如果将 iSkill 的名称修改为 hero1 或者 hero2 都不会报错
@RestController
public class BannerController {
@Autowired
private ISkill hero1; // 或者这里名称叫做 hero2
@GetMapping("/test")
public String test() {
hero1.r();
return "Hello China";
}
}
出现这种的原因就是因为,Spring 会根据 ISkill 接口的类型去推导实现,如果有多个实现的话,会根据具体的名称去判断,但是如果名称也不对的话,那么Spring是不会知道该如果注入,因此会报错。只需要修改名称即可。
那么如果我们不想修改名称怎么办呢?就需要使用 @Autowired 的主动注入,也就是添加一个 @Qualifier 注解
@RestController
public class BannerController {
@Autowired
@Qualifier(value = "hero1")
private ISkill iSkill;
@GetMapping("/test")
public String test() {
iSkill.r();
return "Hello China";
}
}