Spring IoC 容器的核心價值在於依賴注入(DI)實現元件間鬆耦合。本文以經典三層架構(Action → Service → DAO)為例,展示如何透過 XML 配置Setter 注入將介面綁定至實作、層層注入依賴,構建可測試、可擴展、易維護的分層應用。
// DAO 層介面
public interface IStuDAO {
void saveStu();
}
// Service 層介面
public interface IStuService {
void saveStu();
}
// DAO 實作
public class StuDAOImpl implements IStuDAO {
@Override
public void saveStu() {
System.out.println("dao: saving stu...");
}
}
// Service 實作——注入 DAO 介面
public class StuServiceImpl implements IStuService {
private IStuDAO stuDAO; // 依賴介面,而非具體類
@Override
public void saveStu() {
System.out.println("service: saving stu...");
stuDAO.saveStu(); // 委派 DAO
}
// Setter 注入點
public void setStuDAO(IStuDAO stuDAO) { this.stuDAO = stuDAO; }
public IStuDAO getStuDAO() { return stuDAO; }
}
// Action/Controller——注入 Service 介面
public class PersonAction {
private IStuService stuService; // 依賴介面
public void displaySave() {
System.out.println("mvc action: saving stu...");
stuService.saveStu();
}
public void setStuService(IStuService stuService) { this.stuService = stuService; }
public IStuService getStuService() { return stuService; }
}
<beans ...>
<!-- Action 層:注入 Service -->
<bean id="personAction" class="com.lee.spring008.IOC.DI.MVC.PersonAction">
<property name="stuService" ref="stuService"/>
</bean>
<!-- Service 層:注入 DAO -->
<bean id="stuService" class="com.lee.spring008.IOC.DI.MVC.StuServiceImpl">
<property name="stuDAO" ref="stuDAO"/>
</bean>
<!-- DAO 層:無依賴 -->
<bean id="stuDAO" class="com.lee.spring008.IOC.DI.MVC.StuDAOImpl"/>
</beans>
配置解析:
@Test
public void testPersonAction() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonAction person = (PersonAction) context.getBean("personAction");
person.displaySave();
}
mvc action: saving stu...
service: saving stu...
dao: saving stu...
| 維度 | Setter 注入 | 構造器注入 |
|---|---|---|
| 可讀性 | 屬性名明確,XML 易讀 | 參數順序需對應建構子,較隱晦 |
| 不可變性 | 物件建立後可修改依賴 | 建構子注入後不可變,執行緒安全 |
| 循環依賴 | 支援(需配合 `lazy-init`) | 不支援,啟動拋異常 |
| 強制依賴 | 無法強制,易漏注入導致 NPE | 建構子參數天然強制,編譯期保證 |
| 建議場景 | 可選依賴、多屬性、需重新配置 | 核心強制依賴、不可變物件、不可變依賴圖 |
現代 Spring 最佳實踐:核心依賴用構造器注入(`@Autowired` 建構子),可選依賴用 Setter/Field 注入。Spring 4.3+ 單一建構子可省略 `@Autowired`。
// 測試配置:替換 DAO 為 Mock 實作
<bean id="stuDAO" class="com.lee.test.MockStuDAO"/>
// 原 Service、Action 代碼零修改,自動注入 Mock,驗證邏輯隔離
完整專案結構:
https://github.com/leechenxiang/maven-spring001-helloworld
透過 Spring IoC 容器管理 `Action → Service → DAO` 依賴圖,配合介面導向設計與Setter/構造器注入,實現了各層編譯期、執行期雙重解耦。這不僅支援單元測試的 Mock 替換,更為未來微服務拆分、多資料源切換、AOP 橫切關注點植入奠定堅實基礎。掌握 DI 配置細節與選型原則,是 Spring 開發者進階的必修課。