1. 什么是依賴注入(Dependency Injection,DI)?
依賴注入 是 Spring IoC(控制反轉)容器的核心功能。它的目標是將對象的依賴(如其他對象或配置)從對象本身中剝離,由容器負責注入這些依賴。
關鍵概念:
- 依賴: 一個對象需要的其他對象或資源。例如,
UserController
需要UserService
。 - 注入: Spring 容器在創建對象時,將依賴對象傳遞給它,而不是對象自己去創建。
2. Bean 創建與依賴注入的關系
Bean 創建:
- Spring 容器根據定義(如 XML 配置、注解或 Java 配置)實例化一個類,生成一個對象。
依賴注入:
- 創建 Bean 之后,Spring 容器會檢查這個對象是否有依賴項,并將所需的依賴注入進去。
兩者的區別:
- Bean 創建: 生成一個對象的實例。
- 依賴注入: 為創建的對象注入其所需的依賴。
聯系:
- 依賴注入是 Bean 創建過程中的一部分,必須先創建 Bean 才能注入依賴。
3. 依賴注入的三種方式
Spring 提供了三種主要的依賴注入方式:構造器注入、Setter 注入 和 字段注入。
(1) 構造器注入
通過類的構造器將依賴傳遞給對象。
優點:
- 保證依賴在對象創建時就被注入,避免空指針異常。
- 強制依賴項必須提供,增強對象的不可變性。
示例代碼:
@Component
public class UserController {private final UserService userService;// 使用構造器注入@Autowiredpublic UserController(UserService userService) {this.userService = userService;}
}
XML 配置方式:
<bean id="userController" class="com.example.UserController"><constructor-arg ref="userService"/>
</bean>
(2) Setter 注入
通過 Setter 方法注入依賴。
優點:
- 更靈活,可以在對象創建后設置或修改依賴。
- 適合可選依賴的場景。
示例代碼:
@Component
public class UserController {private UserService userService;// 使用 Setter 注入@Autowiredpublic void setUserService(UserService userService) {this.userService = userService;}
}
XML 配置方式:
<bean id="userController" class="com.example.UserController"><property name="userService" ref="userService"/>
</bean>
(3) 字段注入
直接將依賴注入到類的字段上。
優點:
- 簡潔,代碼更少。
- 不需要顯式構造器或 Setter 方法。
缺點:
- 難以單元測試,因為字段是私有的,不能通過構造器或方法替換依賴。
- 不符合 SOLID 原則中的單一責任原則。
示例代碼:
@Component
public class UserController {@Autowiredprivate UserService userService; // 字段注入
}
推薦使用: 構造器注入 > Setter 注入 > 字段注入(特殊情況可用)。
4. Spring 容器如何管理 Bean 的生命周期
Spring 容器通過以下幾個階段管理 Bean 的生命周期:
(1) Bean 的定義和加載
- 通過配置文件(XML、Java 配置、注解)加載 Bean 定義。
- 容器解析 Bean 的依賴關系。
(2) Bean 的實例化
- 容器根據定義,通過構造器或工廠方法實例化 Bean。
(3) 依賴注入
- 容器將所需的依賴對象注入到 Bean 中。
(4) 初始化
- 容器調用初始化方法(如
@PostConstruct
或init-method
)進行初始化邏輯。
(5) Bean 的使用
- Bean 準備就緒后,由應用程序調用。
(6) 銷毀
- 容器關閉時,調用銷毀方法(如
@PreDestroy
或destroy-method
)。
5. 示例場景和常見問題
示例場景:用戶登錄
@Component
public class UserController {private final UserService userService;@Autowiredpublic UserController(UserService userService) {this.userService = userService;}public User login(String username, String password) {return userService.authenticate(username, password);}
}
依賴注入過程:
- Spring 容器加載
UserController
和UserService
的定義。 - 容器創建
UserService
的實例。 - 容器創建
UserController
的實例,并將UserService
注入到它的構造器中。
常見問題:
- 循環依賴問題:A 依賴 B,而 B 也依賴 A,會導致 Bean 無法創建。
- 解決方案: 將其中一個依賴改為 Setter 注入或使用
@Lazy
。
- 解決方案: 將其中一個依賴改為 Setter 注入或使用
- 依賴注入失敗: 如果 Spring 容器中沒有找到需要注入的 Bean,會拋出異常。
- 解決方案: 確保所有需要的 Bean 都被正確注冊。
6. 總結
- 依賴注入的本質: 容器負責將對象需要的依賴注入進來,解除了對象之間的緊耦合。
- Bean 創建與依賴注入: Bean 創建是依賴注入的前提,依賴注入是 Bean 生命周期中的一個步驟。
- 三種注入方式: 構造器注入優先,其次是 Setter 注入,字段注入僅適用于特定場景。
- Spring 容器的管理: 通過完整的生命周期管理,Spring 容器讓開發者專注于業務邏輯。