核心概念
| 特性 | 設值注入 | 建構子注入 |
| 方式 | Setter 方法 / 屬性 | 建構子參數 |
| 強制性 | 選用依賴 | 必要依賴 |
| 不可變性 | 物件建立後可變更 | 建立後不可變 (final) |
| 循環依賴 | 支援 | 不支援 (需 @Lazy 或重構) |
| 測試友善度 | 需手動呼叫 setter | 建構子直接傳入 mock |
詳細優劣勢分析
建構子注入優勢(現代 Spring 推薦)
- 不可變性:依賴在建構時確定,執行期不會意外變更,執行緒安全
- 必要依賴明確:缺少參數編譯即報錯,而非執行期 NPE
- 最終欄位:可搭配
final 關鍵字,編譯器保證初始化一次
- 單元測試簡單:
new Service(new MockRepo()) 無需 Spring 容器
- IDE 支援:重構、查找引用更精準
設值注入適用場景
- 選用依賴:有合理預設值,可不注入也能運作
- 循環依賴:A 需 B、B 需 A 時,至少一方需用設值注入打破循環
- 遗留代碼:大量無參建構子的舊類別
- 框架整合:某些框架要求無參建構子 (如 JPA 實體、部分序列化庫)
Spring 官方演進建議
Spring 4.x 之前:推薦設值注入
Spring 4.x ~ 5.x:兩者並重
Spring 5.1+ / Spring Boot 2.2+:強烈推薦建構子注入
實務最佳模式
@Service
@RequiredArgsConstructor // Lombok 自動產生建構子
public class OrderService {
// 必要依賴:建構子注入 + final
private final OrderRepository orderRepository;
private final PaymentService paymentService;
// 選用依賴:Setter 注入 + @Autowired(required=false)
@Autowired(required = false)
private NotificationService notificationService;
// 或使用 @Lazy 打破循環依賴
@Autowired
@Lazy
private CircularDependencyService circularService;
}
參考資源
CSDN - Spring 注入方式詳細比較