首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Spring IoC 與 DI 核心原理深度解析:從好萊塢原則到三種注入方式與註解驅動實戰

     編輯:Java 綜合教學

Spring IoC 與 DI 核心原理深度解析:從好萊塢原則到三種注入方式與註解驅動實戰

控制反轉 (IoC) 與依賴注入 (DI) 是 Spring 的靈魂。本文從設計哲學 (好萊塢原則) 切入,系統講解 IoC 容器啟動流程、三種注入方式 (構造器/Setter/介面) 代碼實戰、XML 與註解 (@Configuration/@Bean/@Autowired) 雙軌配置、Bean 作用域與生命週期,助你建立完整知識體系。

一、核心哲學:好萊塢原則

"Don't call us, we'll call you." (別找我們,我們會找你)

  • 傳統 (控制正轉):調用者 new 被調用者 → 高耦合、難測試、難替換實現。
  • IoC (控制反轉):容器負責建立對象、管理依賴關係、注入到調用者 → **控制權移交給容器**。
  • DI (依賴注入):IoC 的具體實現手段 —— 容器將依賴「推」給消費者。
  • 本質:IoC 是設計思想,DI 是實現手段,**兩者同一硬幣兩面**。

二、IoC 容器啟動核心流程 (簡化版)

  1. 資源定位:讀取 XML / 掃描註解 (@ComponentScan) / JavaConfig (@Configuration)。
  2. BeanDefinition 註冊:解析元數據 → BeanDefinitionRegistry (Map<String, BeanDefinition>)。
  3. 實例化:反射呼叫建構子 (構造器注入點) → 建立原始對象。
  4. 屬性填充 (DI):Setter/欄位注入、@Autowired 解析依賴 → 遞歸 getBean 獲取依賴。
  5. 初始化:@PostConstruct、InitializingBean.afterPropertiesSet()、init-method。
  6. AOP 代理建立:BeanPostProcessor 後置處理器織入切面 (如 @Transactional 代理)。
  7. 註冊銷毀回調:@PreDestroy、DisposableBean.destroy()、destroy-method。
  8. 容器就緒:getBean(name) 返回完全初始化的 Bean (或代理)。

三、三種注入方式代碼實戰

1. 構造器注入 (推薦:不可變、強依賴、易測試)

// XML
<bean id="userService" class="com.example.UserService">
    <constructor-arg ref="userDao"/>
    <constructor-arg value="defaultRole"/>
</bean>

// JavaConfig (Spring 4.3+ 單構造子可省略 @Autowired)
@Component
public class UserService {
    private final UserDao userDao;
    private final String defaultRole;

    public UserService(UserDao userDao, @Value("${default.role}") String defaultRole) {
        this.userDao = userDao;
        this.defaultRole = defaultRole;
    }
}

2. Setter 注入 (可選依賴、可重新配置)

// XML
<bean id="userService" class="com.example.UserService">
    <property name="userDao" ref="userDao"/>
    <property name="defaultRole" value="guest"/>
</bean>

// 類別
public class UserService {
    private UserDao userDao;
    public void setUserDao(UserDao userDao) { this.userDao = userDao; } // 必須有 setter
}

3. 介面注入 (Spring 不支援,歷史概念)

定義注入介面 Injectable { void inject(Dependency d); },類實現該介面。Spring 拒絕支援,因**侵入性太強** (違背非侵入式原則)。

4. 現代主流:註解驅動 (@Autowired / @Inject / @Resource)

@Service
public class UserService {
    // 欄位注入 (簡潔但隱藏依賴、難測試、不可 final) —— 不推薦生產核心邏輯
    @Autowired private UserDao userDao;

    // Setter 注入 (可選、可重配)
    @Autowired(required = false)
    public void setCache(Cache cache) { this.cache = cache; }

    // 建構子注入 (推薦) + @Value 註入配置
    private final String prefix;
    @Autowired
    public UserService(UserDao userDao, @Value("${app.prefix}") String prefix) {
        this.userDao = userDao; this.prefix = prefix;
    }
}

四、XML vs JavaConfig vs 掃描 三種配置模式對比

模式優點缺點適用場景
XML集中管理、無侵入、動態修改無需重編譯冗長、重構困難、類型不安全舊專案、第三方庫整合、基礎設施 Bean (DataSource, TransactionManager)
JavaConfig (@Configuration + @Bean)類型安全、IDE 重構支援、程式化邏輯 (條件裝配 @Conditional)類編譯耦合、修改需重編譯新專案主流、核心業務配置、複雜條件裝配
組件掃描 (@ComponentScan + @Component/@Service/@Repository/@Controller)極簡、約定優於配置啟動掃描慢、隱式依賴難追蹤、誤掃描風險Controller/Service/Repository 等標準分層

五、Bean 作用域與生命週期

作用域說明Web 環境專屬
singleton (預設)容器單例,全局共享—
prototype每次 getBean 新建實例—
request—單次 HTTP 請求生命週期
session—HTTP Session 生命週期
application—ServletContext 生命週期

生命週期回調順序

建構子 → @Autowired (欄位/Setter) → @PostConstruct → InitializingBean.afterPropertiesSet()
    → init-method (XML) → [AOP 代理] → 就緒可用
    → @PreDestroy → DisposableBean.destroy() → destroy-method (XML) → 容器關閉

六、循環依賴解決機制 (三級快取)

 避免掃描無關類。
    
  • Bean 命名規範:駝峰首字母小寫 (userService),避免衝突。
  • 善用 @Primary / @Qualifier 解決多實現歧義。
  • 測試用 @MockBean / @TestConfiguration 替換依賴。
    1. 上一篇文章:
    2. 下一篇文章:
    Copyright © 程式碼之家 All Rights Reserved