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

Spring IOC 容器 Bean 生命週期完整指南:從創建到銷毀的全流程解析

     編輯:Java 綜合教學

Spring IOC 容器 Bean 生命週期完整指南:從創建到銷毀的全流程解析

Spring IOC 容器管理 Bean 生命週期的能力是框架核心特性之一。理解完整流程、擴展點與執行順序,對於編寫健壯的 Spring 應用、排查初始化順序問題、實現自定義邏輯至關重要。本文基於 Spring 4.x/5.x 源碼,系統梳理 Bean 生命週期七大階段、擴展介面與實戰應用。

一、Bean 生命週期標準流程 (七大階段)

  1. 實例化:透過構造器或工廠方法創建 Bean 實例
  2. 屬性填充:設定 Bean 屬性值與其他 Bean 參考 (依賴注入)
  3. Aware 介面回調:BeanNameAware、BeanFactoryAware、ApplicationContextAware 等
  4. BeanPostProcessor 前置處理:postProcessBeforeInitialization
  5. 初始化:InitializingBean.afterPropertiesSet() → @PostConstruct → init-method
  6. BeanPostProcessor 後置處理:postProcessAfterInitialization (AOP 代理在此生成)
  7. 銷毀:容器關閉時 DisposableBean.destroy() → @PreDestroy → destroy-method

二、XML 配置示範完整生命週期

<bean id="user" class="com.example.User" 
      init-method="init" destroy-method="destroy"
      scope="singleton">
    <property name="userName" value="張三"/>
    <property name="wifeName" value="#{girl.userName}"/> <!-- SpEL -->
</bean>

User 實體類

public class User {
    private String userName;
    private String wifeName;
    // getter/setter 省略

    public User() { System.out.println("1. 構造器執行"); }

    // InitializingBean 介面方法
    public void afterPropertiesSet() { System.out.println("4. afterPropertiesSet()"); }

    // JSR-250 註解 (需啟用 CommonAnnotationBeanPostProcessor)
    @PostConstruct
    public void postConstruct() { System.out.println("5. @PostConstruct"); }

    // XML 配置 init-method
    public void init() { System.out.println("6. init-method"); }

    // DisposableBean 介面方法
    public void destroy() { System.out.println("9. destroy()"); }

    @PreDestroy
    public void preDestroy() { System.out.println("8. @PreDestroy"); }

    // XML 配置 destroy-method
    public void destroyMethod() { System.out.println("10. destroy-method"); }
}

執行順序輸出

1. 構造器執行
2. setUserName(張三)
3. setWifeName(張三)  <-- SpEL 解析
4. afterPropertiesSet()        <-- InitializingBean
5. @PostConstruct              <-- JSR-250
6. init-method                 <-- XML init-method
7. postProcessAfterInitialization()  <-- BeanPostProcessor (AOP 代理生成)
...
容器關閉:
8. @PreDestroy
9. destroy()                   <-- DisposableBean
10. destroy-method             <-- XML destroy-method

三、三大初始化/銷毀機制優先級與對比

機制類型執行順序耦合度推薦度備註
InitializingBean / DisposableBean介面1 / 1高 (Spring 專用)⭐⭐侵入業務代碼
@PostConstruct / @PreDestroy註解 (JSR-250)2 / 2低 (標準規範)⭐⭐⭐⭐⭐首選,需 javax.annotation 依賴 (JDK 9+ 模組化)
init-method / destroy-methodXML 配置3 / 3零 (POJO)⭐⭐⭐⭐第三方類無法加註解時
默認方法名全域預設-零⭐⭐⭐<beans default-init-method="init" default-destroy-method="destroy">

四、核心擴展介面深度解析

1. BeanPostProcessor - 後置處理器 (最強擴展點)

作用:在 Bean 初始化前後攔截、修改、替換、包裝 Bean 實例。對容器中所有 Bean 生效。

public class MyBeanPostProcessor implements BeanPostProcessor {

    // 初始化前:可修改屬性、返回代理對象
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("Before init: " + beanName);
            // 可返回不同對象 (如代理)
        }
        return bean;  // 必須返回非 null
    }

    // 初始化後:AOP 代理在此生成、可進一步包裝
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("user".equals(beanName)) {
            System.out.println("After init: " + beanName);
            // 可修改已初始化的屬性
            ((User) bean).setUserName("修改後名稱");
        }
        return bean;
    }
}

關鍵點:

  • 須在 XML 中聲明 `` (無需 id)
  • 返回 null 會導致 getBean() 返回 null
  • Spring 內建多個 Processor:AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、AspectJAutoProxyCreator (AOP) 等

2. BeanFactoryPostProcessor - BeanFactory 後置處理器

作用:在 Bean 實例化前,讀取/修改 Bean 定義元數據 (BeanDefinition)。

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        // 修改 Bean 定義:scope、lazy-init、屬性值等
        BeanDefinition bd = beanFactory.getBeanDefinition("user");
        bd.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        bd.getPropertyValues().add("userName", "工廠修改");
        
        // 可註冊 BeanPostProcessor
        beanFactory.addBeanPostProcessor(new MyBeanPostProcessor());
    }
}

經典應用:PropertyPlaceholderConfigurer (屬性佔位符解析)、ConfigurationClassPostProcessor (@Configuration 類解析)

執行順序:BeanFactoryPostProcessor (容器啟動早期) → BeanPostProcessor (Bean 初始化前後)

3. InstantiationAwareBeanPostProcessor - 實例化感知後置處理器

繼承 BeanPostProcessor,增加實例化階段攔截:

  • postProcessBeforeInstantiation:實例化前,可返回代理對象跳過預設實例化 (AOP 核心)
  • postProcessAfterInstantiation:實例化後,屬性填充前,返回 false 跳過屬性填充
  • postProcessPropertyValues:屬性填充前,可修改屬性值

建議繼承 InstantiationAwareBeanPostProcessorAdapter 適配器類,僅覆寫所需方法。

五、三種工廠方法創建 Bean

1. 靜態工廠方法

<bean id="dateFormat" class="java.text.DateFormat" factory-method="getDateInstance">
    <constructor-arg value="2"/> <!-- 對應 getDateInstance(int style) -->
</bean>

2. 實例工廠方法

<bean id="simpleDateFormat" class="java.text.SimpleDateFormat">
    <constructor-arg value="yyyy-MM-dd HH:mm:ss"/>
</bean>
<bean id="datetime" factory-bean="simpleDateFormat" factory-method="parse">
    <constructor-arg value="1990-12-12 12:12:12"/>
</bean>

3. FactoryBean 介面 (最靈活、最常用)

public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        User user = new User();
        user.setUserName("FactoryBean創建");
        return user;
    }
    @Override public Class<?> getObjectType() { return User.class; }
    @Override public boolean isSingleton() { return true; }
}

<bean id="user" class="com.example.UserFactoryBean"/>

關鍵差異:注入 user 獲得的是 User 實例而非 UserFactoryBean;若需注入工廠本身,使用 &user。

六、Bean 作用域

Scope生命週期創建時機適用場景
singleton (預設)容器啟動~關閉容器啟動時 (非 lazy-init)無狀態服務、DAO、Controller
prototype每次 getBean 新建每次請求時有狀態物件、Struts2 Action
request單次 HTTP 請求請求開始Web 請求級資料
sessionHTTP Session 週期Session 創建用戶會話資料
applicationServletContext 週期應用啟動全域快取、配置
websocketWebSocket 會話連接建立WebSocket 狀態

七、循環依賴與三級快取機制

Spring 通過三級快取解決單例 Bean 循環依賴 (僅支援 setter/field 注入):

  • 一級快取 singletonObjects:完全初始化好的 Bean
  • 二級快取 earlySingletonObjects:早期暴露的 Bean (實例化完成、屬性未填充)
  • 三級快取 singletonFactories:ObjectFactory 工廠,可生成早期引用 (AOP 代理)

流程:A 實例化 → 放入三級快取 → 屬性填充需 B → B 實例化 → 放入三級快取 → 屬性填充需 A → 從三級快取獲取 A 早期引用 (觸發 AOP 代理) → B 完成 → A 完成 → 移至一級快取。

八、最佳實踐總結

  1. 初始化邏輯優先用 @PostConstruct,銷毀用 @PreDestroy
  2. 第三方類無法加註解時用 XML init-method/destroy-method
  3. 需修改 Bean 定義元數據用 BeanFactoryPostProcessor
  4. 需攔截/包裝 Bean 實例用 BeanPostProcessor
  5. 需在實例化階段干預用 InstantiationAwareBeanPostProcessor
  6. 原型 Bean 銷毀不由容器管理,需自行釋放資源
  7. 循環依賴優先重構設計 (構造器注入、@Lazy、拆分 Bean),無法避免時理解三級快取原理

核心心法:Bean 生命週期是 Spring 容器的心跳。掌握七大階段、三大擴展介面、三級快取機制,能讓你在面對複雜初始化順序、AOP 代理生成時機、循環依賴、第三方庫整合等問題時,從容定位根因並優雅解決。

建議動手調試:在 IDEA 中對 AbstractAutowireCapableBeanFactory.doCreateBean() 打斷點,單步跟蹤完整流程,加深理解。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved