概述
Spring容器能夠通過檢查ApplicationContext
中的內容來實現依賴自動裝配
.
自動轉配的模式
Spring IoC定義了幾種裝配模式可供選擇:
模式 | 解釋 |
---|---|
no | 不開啓自動裝配 |
byName | 通過名稱自動裝配, 在容器中查找名稱然後裝配 |
byType | 通過類型自動裝配, 容器在內部查找匹配的類型進行自動裝配, 如果存在多個會引發致命錯誤, 如果不村子一個則不會報錯 |
constructor | 通過構造函數自動裝配, 和byType類似, 如果不存在bean, 則會報錯 |
自動裝配示例
使用註解方式實現自動裝配, 首先需要對Bean的類標註@Component
或則類似註解來指示Spring IoC這是一個可以由Spring容器管理的Bean的類. 再在需要註釋的構造函數或者字段或則setter方法上標註@Autowired
註解來實現自動注入.
簡單示例
@Component
public class Keyboard {
private String name;
public Keyboard() { }
public Keyboard(String name) {
this.name = name;
}
@Override
public String toString() {
return "Keyboard{" +
"name='" + name + '\'' +
'}';
}
}
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
public class DIDemo {
public static void main(String[] args) {
String scanPackages = "lab.anoper.ioc.di.computer.component";
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
Computer computer = context.getBean("computer",
lab.anoper.ioc.di.computer.component.Computer.class);
System.out.println(computer);
}
}
輸出結果:
Computer{, keyboard=Keyboard{name='null'}}
多個同類型報錯示例
java代碼:
@Configuration
public class ComputerConfig {
@Bean
public Keyboard keyboard1() {
return new Keyboard("keyboard1");
}
@Bean
public Keyboard keyboard2() {
return new Keyboard("keyboard2");
}
}
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
public class Keyboard {
private String name;
public Keyboard() { }
public Keyboard(String name) {
this.name = name;
}
@Override
public String toString() {
return "Keyboard{" +
"name='" + name + '\'' +
'}';
}
}
public class DIDemo {
public static void main(String[] args) {
String scanPackages = "lab.anoper.ioc.di.computer";
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(scanPackages);
Computer computer = context.getBean("computer",
lab.anoper.ioc.di.computer.component.Computer.class);
System.out.println(computer);
}
}
輸出結果:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'lab.anoper.ioc.di.computer.component.Keyboard' available: expected single matching bean but found 2: keyboard1,keyboard2
說明構造函數自動裝配模式下, 當有超過一個同類型bean時候, 會報出致命錯誤.
- 解決方案1: 修改代碼, 使用
@Primary
註解標註一個主要的bean, 則可以成功.
@Configuration
public class ComputerConfig {
@Bean
@Primary
public Keyboard keyboard1() {
return new Keyboard("keyboard1");
}
@Bean
public Keyboard keyboard2() {
return new Keyboard("keyboard2");
}
}
- 解決方案2: 使用
@Qualifier
註解明確需要裝配的bean的名稱.
@Component
public class Computer {
private Keyboard keyboard;
@Autowired
public Computer(@Qualifier("keyboard2") Keyboard keyboard) {
this.keyboard = keyboard;
}
@Override
public String toString() {
return "Computer{" +
", keyboard=" + keyboard +
'}';
}
}
優缺點
優點:
- 減少了屬性配置或者是構造函數配置.
- 在更新代碼時候, 更懂更小, 不必更新依賴關係.
缺點:
- 顯式的申明總是會覆蓋掉自動裝配.
- 不如顯式裝配精確.
- 如果有同一個類型的多個值存在, 可能引發錯誤.
總結
使用@Autowired
註解可以實現自動注入. 配置在屬性字段名上使用setter方法注入, 配置在構造函數上將使用構造函數方式注入. 如果有個同類型的bean則會導致致命注入失敗, 可以使用@Prmiary
註解來確定一個主要組件, 或者在注入點使用@Qualifier
來註明使用的bean的名字.