Spring bean的生命周期

什么是bean的生命周期?

Spring是一個容器, bean是存在于容器中被管理的對象。bean的生命周期就是指bean從實例化到被設置屬性,再到容器銷毀時bean被銷毀的整個過程。

為什么要了解bean的生命周期?

Spring 就是面向 Bean 的編程。如果把Spring比做一個舞臺,那么bean就是舞臺上的演員。Spring 作為Java中最優(yōu)秀的框架之一,已被廣泛的使用,很多第三方框架在設計的時候都考慮到了和Spring的集成,集成的根本其實就是在Spring容器中定義bean。而作為一個優(yōu)秀的框架,Spring很多設計思想都獨具匠心,在bean的整個生命周期過程中預留了很多擴展接口和自定義處理,掌握了bean的生命周期不僅可以學習優(yōu)秀的設計模式,而且對理解 Spring 框架原理有非常好的作用,有助于深入理解Ioc和AOP。

bean生命周期詳解

bean的生命周期不就是實例化,設置屬性,使用完以后被銷毀這么簡單嗎?實例化就是調(diào)用類的構造方法,設置屬性就是調(diào)用setter方法注入,銷毀甚至可以不用定義destroy方法。那么還有那么多要了解的么?

日常開發(fā)中我們定義最多的就是下面這種業(yè)務bean,這類bean的生命周期的確很簡單

<bean id="xxService" class="com.xx.xx.service.impl.xxServiceImpl"/>

除了這類bean的定義,我們在搭建Spring框架時其實還定義了很多bean。其中涉及到
BeanNameAware, BeanFactoryAware, BeanFactoryPostProcessor,InitializingBean, DisposableBean等各種生命周期接口。例如

屬性加載器定義:

    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="ignoreUnresolvablePlaceholders" value="true"/>
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName">
            <value>${jdbc.driverClassName}</value>
        </property>
        ...
    </bean>

線程池定義:

<bean id ="asyncExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="20" />
        <property name="keepAliveSeconds" value="200" />
        <property name="maxPoolSize" value="300" />
        <property name="queueCapacity" value="300" />
        <property name="threadNamePrefix" value="test_asynchronousExecutor" />  
        <property name="threadGroupName" value="test_asynchronousExecutorGroup" />  
    </bean>
下面我們詳細介紹bean的生命周期過程
  1. 生命周期流程


    生命周期流程.png
  2. 各種生命周期接口方法分類

Bean的完整生命周期經(jīng)歷了各種方法調(diào)用,這些方法可以劃分為以下幾類:

1)Bean自身的方法:這個包括了Bean本身調(diào)用的方法和通過配置文件中<bean>的init-method和destroy-method指定的方法

2)Bean級生命周期接口方法:這個包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這些接口的方法

3)容器級生命周期接口方法:這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實現(xiàn),一般稱它們的實現(xiàn)類為“后處理器”。

4)工廠后處理器接口方法:這個包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工廠后處理器  接口的方法。工廠后處理器也是容器級的。在容器啟動裝配配置文件之后立即調(diào)用。 (PropertyPlaceholderConfigurer其實就是一個工廠后處理器接口的實現(xiàn))

3.代碼演示

1)定義一個bean,調(diào)用Bean自身的方法和Bean級生命周期接口方法。它實現(xiàn)了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這4個接口,同時有2個方法,對應配置文件中<bean>的init-method和destroy-method

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("【構造器】調(diào)用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接口】調(diào)用BeanFactoryAware.setBeanFactory()");
        this.beanFactory = arg0;
    }

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

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

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

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

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

2)容器級生命周期接口BeanPostProcessor。BeanPostProcessor接口包括2個方法postProcessAfterInitialization和postProcessBeforeInitialization,這兩個方法的第一個參數(shù)都是要處理的Bean對象,第二個參數(shù)都是Bean的name。返回值也都是要處理的Bean對象

public class MyBeanPostProcessor implements BeanPostProcessor {

    public MyBeanPostProcessor() {
        super();
        System.out.println("這是BeanPostProcessor實現(xiàn)類構造器??!");
    }

    @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;
    }
}

3)工廠后處理器接口方法

public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        super();
        System.out.println("這是BeanFactoryPostProcessor實現(xiàn)類構造器??!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory arg0)
            throws BeansException {
        System.out
                .println("BeanFactoryPostProcessor調(diào)用postProcessBeanFactory方法");
        BeanDefinition bd = arg0.getBeanDefinition("person");
        bd.getPropertyValues().addPropertyValue("phone", "110");
    }

}

4)配置文件

<?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"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans 
            http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

    <bean id="beanPostProcessor" class="springBeanTest.MyBeanPostProcessor">
    </bean>

    <bean id="beanFactoryPostProcessor" class="springBeanTest.MyBeanFactoryPostProcessor">
    </bean>
    
    <bean id="person" class="springBeanTest.Person" init-method="myInit"
        destroy-method="myDestory" scope="singleton" p:name="張三" p:address="武漢"
        p:phone="15900000000" />

</beans>

5)測試代碼

public class BeanLifeCycle {

    public static void main(String[] args) {

        System.out.println("現(xiàn)在開始初始化容器");
        
        ApplicationContext factory = new ClassPathXmlApplicationContext("springBeanTest/beans.xml");
        System.out.println("容器初始化成功");    
        //得到Preson,并使用
        Person person = factory.getBean("person",Person.class);
        System.out.println(person);
        
        System.out.println("現(xiàn)在開始關閉容器!");
        ((ClassPathXmlApplicationContext)factory).registerShutdownHook();
    }
}

運行結果:

現(xiàn)在開始初始化容器
這是BeanFactoryPostProcessor實現(xiàn)類構造器!!
BeanFactoryPostProcessor調(diào)用postProcessBeanFactory方法
這是BeanPostProcessor實現(xiàn)類構造器??!
【構造器】調(diào)用Person的構造器實例化
【注入屬性】注入屬性address
【注入屬性】注入屬性name
【注入屬性】注入屬性phone
【BeanNameAware接口】調(diào)用BeanNameAware.setBeanName()
【BeanFactoryAware接口】調(diào)用BeanFactoryAware.setBeanFactory()
BeanPostProcessor接口方法postProcessBeforeInitialization對屬性進行更改!
【InitializingBean接口】調(diào)用InitializingBean.afterPropertiesSet()
【init-method】調(diào)用<bean>的init-method屬性指定的初始化方法
BeanPostProcessor接口方法postProcessAfterInitialization對屬性進行更改!
容器初始化成功
Person [address=武漢, name=張三, phone=110]
現(xiàn)在開始關閉容器!
【DiposibleBean接口】調(diào)用DiposibleBean.destory()
【destroy-method】調(diào)用<bean>的destroy-method屬性指定的初始化方法

現(xiàn)在回過頭來看看propertyConfigurer這個bean,它其實不是普通的bean,就是一個工廠后處理器,在容器啟動的時候,它的postProcessBeanFactory方法被調(diào)用,方法邏輯就是從配置的locations路徑中尋找properties文件,將文件內(nèi)容轉(zhuǎn)換為map對象,然后將容器中其他所有bean(其他是指非容器級生命周期接口的bean和非工廠后處理器的bean) <property>中的占位符替換成配置文件中的值。等到所有占位符替換完成,bean就可以正常的初始化了。

說到bean的生命周期,不得不提一下FactoryBean接口,它和BeanFactory名字非常類似,但是含義卻千差萬別。 它是一個特殊的接口,實現(xiàn)了此接口的bean,容器將調(diào)用接口的getObject()方法得到該bean對象,而不是調(diào)用類的構造方法。除此之外,其他生命周期和前面描述的一樣。

FactoryBean實際應用:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="xxx_master" />
        <property name="mapperLocations">
            <array>
                <value>classpath*:mapper/**/*.xml</value>
            </array>
        </property>
    </bean>
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容