控制反轉 (IoC) 將對象創建與依賴管理權交給容器。DI 是 IoC 的具體實現方式:
new 依賴,強耦合,難測試// 傳統:強耦合
public class TextEditor {
private SpellChecker spellChecker = new SpellChecker(); // 內部創建
}
// DI:鬆耦合
public class TextEditor {
private SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) { // 建構子注入
this.spellChecker = spellChecker;
}
public void setSpellChecker(SpellChecker spellChecker) { // Setter 注入
this.spellChecker = spellChecker;
}
}
透過建構子參數注入依賴,適合強制依賴、不可變對象。
<bean id="textEditor" class="com.example.di.TextEditor">
<constructor-arg ref="spellChecker"/>
</bean>
<bean id="spellChecker" class="com.example.di.SpellChecker"/>
| 情境 | 解決方案 | 範例 |
|---|---|---|
| 單一參數 | 直接匹配 | <constructor-arg ref="bean"/> |
| 多參數、類型不同 | 按聲明順序匹配 | <constructor-arg ref="a"/><constructor-arg ref="b"/> |
| 多參數、類型相同 | 指定 type 或 index |
<constructor-arg type="int" value="2024"/> |
| 明確指定位置 | index 屬性 (0-based) |
<constructor-arg index="0" value="2024"/> |
ref="beanId":注入其他 Bean 實例value="literal":注入字面值 (基本類型、String)透過 Setter 方法注入,適合可選依賴、可變對象、循環依賴場景。
<bean id="textEditor" class="com.example.di.TextEditor">
<property name="spellChecker" ref="spellChecker"/>
</bean>
<bean id="spellChecker" class="com.example.di.SpellChecker"/>
屬性名 spellChecker → Setter setSpellChecker(),遵循 JavaBean 規範。
Spring 2.0+ 提供 p: 命名空間,屬性注入更簡潔。
<!-- 傳統 -->
<bean id="john" class="com.example.Person">
<property name="name" value="John Doe"/>
<property name="spouse" ref="jane"/>
</bean>
<!-- p-namespace -->
<beans xmlns:p="https://www.springframework.org/schema/p" ...>
<bean id="john" class="com.example.Person"
p:name="John Doe" p:spouse-ref="jane"/>
<bean name="jane" class="com.example.Person" p:name="Jane Doe"/>
</beans>
p:propertyName="value":字面值注入p:propertyName-ref="beanId":Bean 參考注入 (-ref 後綴)| 維度 | 建構子注入 | Setter 注入 |
|---|---|---|
| 依賴性質 | 強制、不可變 | 可選、可變 |
| 不可變性 | 支援 final 欄位 | 不支援 |
| 循環依賴 | 無法解決 | 可解決 |
| 可讀性 | 依賴集中在建構子 | 分散在多個 Setter |
| 向後相容 | 新增參數破壞相容 | 新增 Setter 不影響 |
| Spring 團隊建議 | 推薦 (Spring 4.0+) | 次要選擇 |
@Autowired、@Required、@Value、建構子單參數可省略 @Autowired@Value("${prop.name}") 讀取 properties/yml// SpellChecker.java
public class SpellChecker {
public SpellChecker() { System.out.println("SpellChecker created"); }
public void checkSpelling() { System.out.println("Checking..."); }
}
// TextEditor.java (建構子注入版)
public class TextEditor {
private final SpellChecker spellChecker;
public TextEditor(SpellChecker spellChecker) { // 單參數建構子,Spring 4.0+ 自動注入
this.spellChecker = spellChecker;
}
public void spellCheck() { spellChecker.checkSpelling(); }
}
// beans.xml
<bean id="spellChecker" class="com.example.di.SpellChecker"/>
<bean id="textEditor" class="com.example.di.TextEditor">
<constructor-arg ref="spellChecker"/>
</bean>