@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";
}
}