Spring Framework核心概念之Bean生命週期管理

目錄

Spring Bean的生命週期

Spring容器既Application或者WebApplication會在管理Bean的時候;爲了儘可能的把自己內部的東西機制暴露出來給用戶使用,所以在Bean創建的過程中加了很多機制,通過所謂的"處理器"Processor暴露出來,然後處理器都有自己的順序,我們需要做的就是定義好處理器的邏輯,然後註冊到Sprinhg容器中,Spring就會調用了。下面就是Spring管理Bean的生命週期圖。

img

img

下面這張圖描述的更爲詳細。

相關接口的分類

對於上面圖看不懂不要着急因爲你並不認識與生命週期相關的接口。Spring生命週期你可以理解爲四個等級;每個等級中都用有相應的接口,實現其中某個接口或者將實現類注入到Sprng容器,容器就會在相應的時機調用其方法。詳細信息可看下面的一個表格。

  • 工廠後處理器接口方法
  • 容器級生命週期接口方法
  • Bean級生命週期接口方法
  • Bean本身方法
分類 接口 調用時間
工廠後處理器接口 BeanFactoryPostProcessor 容器創建完畢,裝配Bean源後立即調用
容器後處理器接口 InstantiationAwareBeanPostProcessor 分別在調用構造之前,注入屬性之前,實例化完成時調用
容器後處理器接口 BeanPostProcessor 分別在Bean的初始化方法調用前後執行
Bean級後置處理器接口 BeanNameAware 注入屬性後調用
Bean級後置處理器接口 BeanFactoryAware 注入屬性後調用
Bean級後置處理器接口 InitializingBean 在類本身的初始化方法之前調用其方法(本身也是初始化方法)
Bean級後置處理器接口 DiposableBean 在類本身的銷燬方法執行之前調用其方法(本身也是銷燬方法)
Bean本身方法 init方法 在注入屬性之後調用初始化方法
Bean本身方法 destroy方法 在關閉容器的時候進行銷燬

測試SpringBean生命週期的Demo程序

本測試程序來自https://www.cnblogs.com/zrtqsk/p/3735273.html 我在這裏說一下測試程序是如何測試SpringBean的生命週期的。首先將一個工廠後處理器 BeanFactoryPostProcessor接口實現注入容器,再將容器後處理器InstantiationAwareBeanPostProcessorBeanPostProcessor注入容器,又在自定義Person實現了Bean級後處理器BeanNameAwareBeanFactoryAwareInitializingBeanDiposableBean接口的相關方法,最後就是在自定義的Person類中實現了其本身的init()方法和destroy()方法。

  • 自定義Person類
public class Person implements BeanFactoryAware, BeanNameAware,
        InitializingBean, DisposableBean {

    private String name;
    private String address;
    private int phone;

    private BeanFactory beanFactory;
    private String beanName;

    public Person() {
        System.out.println("【構造器】調用Person的構造器實例化");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("【注入屬性】注入屬性name");
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        System.out.println("【注入屬性】注入屬性address");
        this.address = address;
    }

    public int getPhone() {
        return phone;
    }

    public void setPhone(int phone) {
        System.out.println("【注入屬性】注入屬性phone");
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Person [address=" + address + ", name=" + name + ", phone="
                + phone + "]";
    }

    // 這是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory arg0) throws BeansException {
        System.out
                .println("【BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()");
        this.beanFactory = arg0;
    }

    // 這是BeanNameAware接口方法
    @Override
    public void setBeanName(String arg0) {
        System.out.println("【BeanNameAware接口】調用BeanNameAware.setBeanName()");
        this.beanName = arg0;
    }

    // 這是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out
                .println("【InitializingBean接口】調用InitializingBean.afterPropertiesSet()");
    }

    // 這是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("【DiposibleBean接口】調用DiposibleBean.destory()");
    }

    // 通過<bean>的init-method屬性指定的初始化方法
    public void myInit() {
        System.out.println("【init-method】調用<bean>的init-method屬性指定的初始化方法");
    }

    // 通過<bean>的destroy-method屬性指定的初始化方法
    public void myDestory() {
        System.out.println("【destroy-method】調用<bean>的destroy-method屬性指定的初始化方法");
    }
}
  • MyBeanPostProcessor (實現容器級別後置處理器)
public class MyBeanPostProcessor implements BeanPostProcessor {
    public MyBeanPostProcessor() {
        super();
        System.out.println("這是BeanPostProcessor實現類構造器!!");
        // TODO Auto-generated constructor stub
    }

    @Override
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out
                .println("BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!");
        return arg0;
    }

    @Override
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        System.out
                .println("BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!");
        return arg0;
    }
}
  • MyInstantiationAwareBeanPostProcessor(實現容器級別後置處理器)
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    public MyInstantiationAwareBeanPostProcessor() {
        super();
        System.out
                .println("這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!");
    }

    // 接口方法、實例化Bean之前調用
    @Override
    public Object postProcessBeforeInstantiation(Class beanClass,
                                                 String beanName) throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法");
        return null;
    }

    // 接口方法、實例化Bean之後調用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
            throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法");
        return bean;
    }

    // 接口方法、設置某個屬性時調用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName)
            throws BeansException {
        System.out
                .println("InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法");
        return pvs;
    }
}
  • MyBeanFactoryPostProcessor (實現容器級別後置處理器)
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("這是BeanFactoryPostProcessor實現類構造器!!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("BeanFactoryPostProcessor調用postProcessBeanFactory方法");
        BeanDefinition bd = arg0.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }
}
  • 配置Spring的xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="beanPostProcessor" class="com.jimisun.learnspringboot.web.MyBeanPostProcessor">
    </bean>

    <bean id="instantiationAwareBeanPostProcessor"
          class="com.jimisun.learnspringboot.web.MyInstantiationAwareBeanPostProcessor">
    </bean>

    <bean id="beanFactoryPostProcessor" class="com.jimisun.learnspringboot.web.MyBeanFactoryPostProcessor">
    </bean>

    <bean id="person" class="com.jimisun.learnspringboot.web.Person" init-method="myInit"
          destroy-method="myDestory" scope="singleton" p:name="張三" p:address="廣州"
          p:phone="15900000000"/>

</beans>
  • Main方法執行測試
public class Main {
    public static void main(String[] args) {

        System.out.println("現在開始初始化容器");

        ApplicationContext factory = new ClassPathXmlApplicationContext("bens.xml");
        System.out.println("容器初始化成功");
        //得到Preson,並使用
        Person person = factory.getBean("person",Person.class);
        System.out.println(person);

        System.out.println("現在開始關閉容器!");
        ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
    }

}
  • 測試結果(我對Main方法執行結果做了格式化,方便參照)

LOGGER測試:現在開始初始化容器
    【工廠構造】這是BeanFactoryPostProcessor實現類構造器!!
    【工廠方法】BeanFactoryPostProcessor調用postProcessBeanFactory方法
        【容器構造】這是BeanPostProcessor實現類構造器!!
        【容器構造】這是InstantiationAwareBeanPostProcessorAdapter實現類構造器!!
        【容器方法】InstantiationAwareBeanPostProcessor調用postProcessBeforeInstantiation方法
            【類構造】調用Person的構造器實例化
        【容器方法】InstantiationAwareBeanPostProcessor調用postProcessPropertyValues方法
                【類注入屬性】注入屬性address
                【類注入屬性】注入屬性name
                【類注入屬性】注入屬性phone
                【Bean方法:BeanNameAware接口】調用BeanNameAware.setBeanName()
                【Bean方法:BeanFactoryAware接口】調用BeanFactoryAware.setBeanFactory()
            【容器方法】BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
                【Bean方法:InitializingBean接口】調用InitializingBean.afterPropertiesSet()
                【自身方法:init-method】調用<bean>的init-method屬性指定的初始化方法
            【容器方法】BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
        【容器方法】InstantiationAwareBeanPostProcessor調用postProcessAfterInitialization方法
LOGGER測試:容器初始化成功
    Person [address=廣州, name=張三, phone=110]
LOGGER測試:現在開始關閉容器!
                【Bean級別:DiposibleBean接口】調用DiposibleBean.destory()
                【自身方法:destroy-method】調用<bean>的destroy-method屬性指定的初始化方法

將Demo代碼的執行結果與上述表中的執行時機進行對比,看看執行時機是否正確,

小結

理解透徹Spring Bean的生命週期對開發中可以解決比較棘手的問題,對於深入學習Spring Framework框架這是必須要掌握的知識,所以可以多看兩遍。

該教程所屬Java工程師之Spring Framework深度剖析專欄,本系列相關博文目錄 Java工程師之Spring Framework深度剖析專欄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章