Spring之bean的生命周期

Spring之bean的生命周期

在傳統的Java應用中,bean的生命周期很簡單,使用Java關鍵字 new 進行Bean 的實例化,然後該Bean 就能夠使用了。一旦bean不再被使用,則由Java自動進行垃圾回收。

相比之下,Spring管理Bean的生命周期就複雜多了,正確理解Bean 的生命周期非常重要,因為Spring對Bean的管理可擴展性非常強,下面展示了一個Bean的構造過程

image

  1. Bean 容器找到配置文件中 Spring Bean 的定義。
  2. Bean 容器利用 Java Reflection API 創建一個 Bean 的實例。
  3. 如果涉及到一些屬性值 利用 set()方法設置一些屬性值。
  4. 如果實現了其他 *.Aware介面,就調用相應的方法。
  5. 如果有和載入這個 Bean 的 Spring 容器相關的 BeanPostProcessor 對象,執行postProcessBeforeInitialization() 方法
  6. 如果 Bean 實現了InitializingBean介面,執行afterPropertiesSet()方法。
  7. 如果 Bean 在配置文件中的定義包含 init-method 屬性,執行指定的方法。
  8. 如果有和載入這個 Bean 的 Spring 容器相關的 BeanPostProcessor 對象,執行postProcessAfterInitialization() 方法
  9. 當要銷毀 Bean 的時候,如果 Bean 實現了 DisposableBean 介面,執行 destroy() 方法。
  10. 當要銷毀 Bean 的時候,如果 Bean 在配置文件中的定義包含 destroy-method 屬性,執行指定的方法。

BeanFactory 的注釋里,有這麼一段話,如下圖所示:
image

程式碼演示

  1. 新建一個 User 類,讓其實現介面 BeanNameAwareBeanFactoryAwareInitializingBeanDiposableBean 這4個介面,以及編寫userInit()userDestroy() 兩個方法,對應配置文件中 <bean>init-methoddestroy-method
package com.wqing.domain;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

/**
 * @Description 用於演示 Bean 的生命周期
 * @Author wqing
 * @Date 2022/8/11 15:37
 */
public class User implements BeanNameAware, BeanFactoryAware,
        InitializingBean, DisposableBean {
    private String name;
    private Integer age;

    private BeanFactory beanFactory;
    private String beanName;

    public User() {
        System.out.println("[構造器]--調用Person的構造函數進行實例化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("[屬性填充]--注入屬性name");
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        System.out.println("[屬性填充]--注入屬性age");
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //這是 BeanFactoryAware 介面的方法
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("[BeanFactoryAware]--執行BeanFactoryAware.setBeanFactory(),beanFactory為:" + beanFactory);
        this.beanFactory = beanFactory;
    }

    //這是 BeanNameAware 介面的方法
    @Override
    public void setBeanName(String name) {
        System.out.println("[BeanNameAware]--執行BeanNameAware.setBeanName(),beanName為: " + name);
        this.beanName = name;
    }

    //這是 DisposableBean 介面的方法
    @Override
    public void destroy() throws Exception {
        System.out.println("[DisposableBean]--執行DisposableBean.destroy()");
    }

    //這是 InitializingBean 介面的方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("[InitializingBean]--執行InitializingBean.afterPropertiesSet()");
    }

    // 通過<bean>的init-method屬性指定的初始化方法
    public void userInit() {
        System.out.println("[init-method]--執行<bean>的init-method屬性指定的初始化方法");
    }

    // 通過<bean>的destroy-method屬性指定的初始化方法
    public void userDestroy() {
        System.out.println("[destroy-method]--執行<bean>的destroy-method屬性指定的銷毀方法");
    }
}

  1. 自定義 MyBeanPostProcessor 實現 BeanPostProcessor
package com.wqing.domain;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @Description
 * @Author 王清
 * @Date 2022/8/11 16:06
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
     * 實例化、依賴注入完畢,在調用顯示的初始化之前完成一些訂製的初始化任務
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[BeanPostProcessor]--執行BeanPostProcessor.postProcessBeforeInitialization()");
        return bean;
    }

    /**
     * 實例化、依賴注入、初始化完畢時執行
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("[BeanPostProcessor]--執行BeanPostProcessor.postProcessAfterInitialization()");
        return bean;
    }
}

BeanPostProcessor 介面包括2個方法 postProcessAfterInitializationpostProcessBeforeInitialization,這兩個方法的第一個參數都是要處理的Bean對象,第二個參數都是Bean的name。返回值也都是要處理的Bean對象。

  1. 編寫 application.xml,將 UserMyBeanPostProcessor 註冊進容器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="//www.springframework.org/schema/beans"
       xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="//www.springframework.org/schema/beans //www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.wqing.domain.User" init-method="userInit"
          destroy-method="userDestroy">
        <property name="name" value="張三"/>
        <property name="age" value="20"/>
    </bean>

    <bean id="myBeanPostProcessor" class="com.wqing.domain.MyBeanPostProcessor"/>
</beans>
  1. 編寫測試類
package com.wqing;

import com.wqing.domain.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @Description
 * @Author wqing
 * @Date 2022/8/5 14:38
 */
public class Test {
    public static void main(String[] args) {
        System.out.println("容器開始創建");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
        User bean = context.getBean(User.class);
        System.out.println("使用 bean");
        System.out.println(bean);
        System.out.println("容器開始銷毀");
        context.close();
    }
}

執行結果

容器開始創建
[構造器]--調用Person的構造函數進行實例化
[屬性填充]--注入屬性name
[屬性填充]--注入屬性age
[BeanNameAware]--執行BeanNameAware.setBeanName(),beanName為: user
[BeanFactoryAware]--執行BeanFactoryAware.setBeanFactory(),beanFactory為:org.springframework.beans.factory.support.DefaultListableBeanFactory@38082d64: defining beans [user,myBeanPostProcessor]; root of factory hierarchy
[BeanPostProcessor]--執行BeanPostProcessor.postProcessBeforeInitialization()
[InitializingBean]--執行InitializingBean.afterPropertiesSet()
[init-method]--執行<bean>的init-method屬性指定的初始化方法
[BeanPostProcessor]--執行BeanPostProcessor.postProcessAfterInitialization()
使用 bean
User{name='張三', age=20}
容器開始銷毀
[DisposableBean]--執行DisposableBean.destroy()
[destroy-method]--執行<bean>的destroy-method屬性指定的銷毀方法
Tags: