IoC(Inversion of Control,控制反轉)與 DI(Dependency Injection,依賴注入)是 Spring 框架的靈魂。許多開發者知其然不知其所以然,本文將透過四個漸進式範例,從「緊耦合」演進到「容器管理」,再引入「服務定位器」,最終落地「依賴注入」,並附上完整程式碼與執行序列分析,帶你徹底看懂 Spring 核心機制。
ReportService 直接 new PDFGenerator(),無法切換實作。Map<String,Object> 管理 Bean,ReportService 透過 Container.getBean() 取得依賴,但仍屬「主動拉取」。ServiceLocator 隔離查找邏輯,但 ReportService 仍需主動呼叫。ReportService 時「推」入依賴(Setter 注入),控制權反轉給容器,達成真正解耦。class Container {
private static Map<String, Object> beans = new HashMap<>();
public Container() {
// 1. 先建立被注入的依賴
ReportGenerator generator = new PDFGenerator();
beans.put("reportGenerator", generator);
// 2. 建立服務並「注入」依賴
ReportService service = new ReportService();
service.setReportGenerator(generator); // 關鍵:Setter 注入
beans.put("reportService", service);
}
public static Object getBean(String id) { return beans.get(id); }
}
class ReportService {
private ReportGenerator generator; // 無建構子參數,僅提供 Setter
public void setReportGenerator(ReportGenerator g) { this.generator = g; }
public void getDailyReport(Date d) { generator.generate(new Table()); }
}
1...開始初始化 Container ...
2...開始初始化 PDFGenerator ...
3...開始初始化 ReportService ...
4...開始注入 ReportGenerator ...
5...完成初始化 Container ...
最後獲取服務組件...getBean() --> reportService ...
generate an PDF report ...
由輸出可見:容器啟動時依序完成「實例化依賴 → 實例化服務 → 注入依賴」,客戶端僅需 getBean 即可取得已組裝完成的服務,完全不感知具體實作類別。
掌握這四階段演進,不僅能讀懂 Spring 原始碼,更能在面試與架構設計中遊刃有餘。