天天看點

Spring之Bean的生命周期詳解

 通過前面多個接口的介紹了解了Bean對象生命周期相關的方法,本文就将這些接口的方法串起來,來了解Bean的完整的生命周期。而介紹Bean的生命周期也是面試過程中經常會碰到的一個問題,如果不注意就跳坑裡啦~~

Spring之Bean對象的初始化和銷毀方法

Spring之InitializingBean接口和DisposableBean接口介紹

Spring之Aware接口介紹

Spring之InstantiationAwareBeanPostProcessor接口介紹

Spring之BeanFactoryPostProcessor接口介紹

Spring之BeanPostProcessor(後置處理器)介紹

建議:看此文前請将上面相關的内容熟悉下,便于了解下面的内容。

文章目錄

   Bean生命周期

       一、調用過程

       二、生命周期方法說明

       三、示範

           1.BeanFactoryPostProcessor接口

           2.BeanPostProcessor接口

           3.InstantiationAwareBeanPostProcessor接口

           4.BeanNameAware,BeanFactoryAware等Aware接口

           5.InitializingBean,DisposableBean接口

           6.@PostConstruct和@PreDestroy注解

           7.init-method,destroy-method

           8.測試

       四、Bean對象生命周期總結

Bean生命周期

一、調用過程

Spring之Bean的生命周期詳解

二、生命周期方法說明

接口 方法 說明

BeanFactoryPostProcessor postProcessBeanFactory 在Bean對象執行個體化之前執行, 通過beanFactory可以擷取bean的定義資訊, 并可以修改bean的定義資訊。這點是和BeanPostProcessor最大差別

BeanPostProcessor postProcessBeforeInitialization 執行個體化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務

postProcessAfterInitialization 執行個體化、依賴注入、初始化完畢時執行

InstantiationAwareBeanPostProcessor postProcessBeforeInstantiation 在方法執行個體化之前執行,傳回結果為null正常執行,傳回結果如果不為null則會跳過相關方法而進入初始化完成後的流程

postProcessAfterInstantiation 在方法執行個體化之後執行,傳回結果true才會執行postProcessPropertyValues方法

postProcessPropertyValues 可以用來修改Bean中屬性的内容

InitializingBean afterPropertiesSet 初始化的方法

DisposableBean destroy 容器銷毀前的回調方法

Aware setXXX 感覺對應Spring容器的内容

@PostConstruct 标注在方法頭部,表示初始化的方法

@PreDestroy 标注在方法頭部,表示銷毀前回調的方法

init-method屬性 指定初始化的方法

destory-method屬性 指定銷毀前的回調方法

三、示範

1.BeanFactoryPostProcessor接口

 該接口中的方法是最先執行的。在Bean執行個體化之前執行

/**
 * 自定義BeanFactoryPostProcessor
 * 
 * @author dengp
 *
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    /**
     * 本方法在Bean對象執行個體化之前執行,
     * 通過beanFactory可以擷取bean的定義資訊,
     * 并可以修改bean的定義資訊。這點是和BeanPostProcessor最大差別
     */
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        
        System.out.println("****** BeanFactoryPostProcessor 開始執行了");
        /*String[] names = beanFactory.getBeanDefinitionNames();
        for (String name : names) {
            if("user".equals(name)){
                
                BeanDefinition beanDefinition = beanFactory.getBeanDefinition(name);
                MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
                // MutablePropertyValues如果設定了相關屬性,可以修改,如果沒有設定則可以添加相關屬性資訊
                if(propertyValues.contains("name")){
                    propertyValues.addPropertyValue("name", "bobo");
                    System.out.println("修改了屬性資訊");
                }
            }
        }*/
        System.out.println("******* BeanFactoryPostProcessor 執行結束了");
    }
}      

2.BeanPostProcessor接口

 該接口中定義了兩個方法,分别在Bean對象執行個體化及裝配後在初始化的前後執行

/**
 * 自定義BeanPostProcessor實作類
 * BeanPostProcessor接口的作用是:
 *   我們可以通過該接口中的方法在bean執行個體化、配置以及其他初始化方法前後添加一些我們自己的邏輯
 * @author dengp
 *
 */
public class MyBeanPostProcessor implements BeanPostProcessor{

    /**
     * 執行個體化、依賴注入完畢,在調用顯示的初始化之前完成一些定制的初始化任務
     * 注意:方法傳回值不能為null
     * 如果傳回null那麼在後續初始化方法将報空指針異常或者通過getBean()方法擷取不到bena執行個體對象
     * 因為後置處理器從Spring IoC容器中取出bean執行個體對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println(">>後置處理器 before方法:"+bean+"\t"+beanName);
        }
        
        // 可以根據beanName不同執行不同的處理操作
        return bean;
    }

    /**
     * 執行個體化、依賴注入、初始化完畢時執行 
     * 注意:方法傳回值不能為null
     * 如果傳回null那麼在後續初始化方法将報空指針異常或者通過getBean()方法擷取不到bena執行個體對象
     * 因為後置處理器從Spring IoC容器中取出bean執行個體對象沒有再次放回IoC容器中
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println("<<後置處理器after方法:"+bean+"\t"+beanName);
        }
        // 可以根據beanName不同執行不同的處理操作
        return bean;
    }
}      

3.InstantiationAwareBeanPostProcessor接口

 該接口是BeanPostProcessor接口的子接口,是以該接口肯定具有BeanPostProcessor接口的功能,同時又定義了三個自己的接口,這三個接口是在Bean執行個體化前後執行的方法。

/**
 * 自定義處理器
 * @author dengp
 *
 */
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor{

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定義初始化方法之前執行
     * Bean對象已經存在了
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // TODO Auto-generated method stub
        if("user".equals(beanName)){
            System.out.println("【---InstantiationAwareBeanPostProcessor---】 postProcessBeforeInitialization");
        }
        
        return bean;
    }

    /**
     * BeanPostProcessor接口中的方法
     * 在Bean的自定義初始化方法執行完成之後執行
     * Bean對象已經存在了
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println("【--InstantiationAwareBeanPostProcessor----】 postProcessAfterInitialization");
        }
        return bean;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 在方法執行個體化之前執行  Bean對象還沒有
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessBeforeInstantiation");
        }
        return null;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 在方法執行個體化之後執行  Bean對象已經建立出來了
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessAfterInstantiation");
        }
        return true;
    }

    /**
     * InstantiationAwareBeanPostProcessor中自定義的方法
     * 可以用來修改Bean中屬性的内容
     */
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
            String beanName) throws BeansException {
        if("user".equals(beanName)){
            System.out.println("【--InstantiationAwareBeanPostProcessor----】postProcessPropertyValues--->");
        }
        return pvs;
    }
}      

4.BeanNameAware,BeanFactoryAware等Aware接口

 Aware接口是用來讓對象感覺目前的IOC環境

5.InitializingBean,DisposableBean接口

 這兩個接口是Bean初始化及銷毀回調的方法。

6.@PostConstruct和@PreDestroy注解

package com.dpb.pojo;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/**
 * 實作InitializingBean和DisposableBean接口
 * @author dengp
 *
 */
public class User implements InitializingBean,DisposableBean,BeanNameAware,BeanFactoryAware{

    private int id;
    
    private String name;
    //感覺本對象在Spring容器中的id屬性
    private String beanName;
    // 感覺本對象所屬的BeanFactory對象
    private BeanFactory factory;
    
    public User(){
        System.out.println("構造方法被執行了...User 被執行個體化");
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getBeanName() {
        return beanName;
    }

    
    @Override
    public String toString() {
        return "User [id=" + id + ", name=" + name + ", beanName=" + beanName + "]";
    }

    /**
     * bean對象銷毀前的回調方法
     */
    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("《DisposableBean接口》destory ....");
    }

    /**
     * 初始化的方法
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("初始化:《InitializingBean接口》afterPropertiesSet....");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        // TODO Auto-generated method stub
        System.out.println("【BeanFactoryAware接口】setBeanFactory");
        this.factory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        System.out.println("【BeanNameWare接口】setBeanName");
        this.beanName = name;
    }

    public BeanFactory getFactory() {
        return factory;
    }

    /**
     * 也是個初始化的方法
     */
    @PostConstruct
    public void postConstruct(){
        System.out.println("初始化:【@PostConstruct】執行了...");
    }
    /**
     * 銷毀前的回調方法
     */
    @PreDestroy
    public void preDestory(){
        System.out.println("【@preDestory】執行了...");
    } 
    /**
     * 初始化的方法
     * 通過bean标簽中的 init-method屬性指定
     */
    public void start(){
        System.out.println("初始化:【init-method】方法執行了....");
    }
    
    /**
     * 銷毀前的回調方法
     * 通過bean标簽中的 destory-method屬性指定
     */
    public void stop(){
        System.out.println("【destory-method】方法執行了....");
    }
}      

7.init-method,destroy-method

<?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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
    <context:annotation-config/>

    <bean class="com.dpb.pojo.User" id="user" init-method="start" destroy-method="stop" >
        <property name="name" value="波波烤鴨"></property>
    </bean>
    
    <!-- 注冊後置處理器 -->
    <bean class="com.dpb.processor.MyBeanPostProcessor"/>
    
    
    <!-- 注冊 InstantiationAwareBeanPostProcessor -->
    <bean class="com.dpb.processor.MyInstantiationAwareBeanPostProcessor"></bean>
    <!-- 注冊 BeanFactoryPostProcessor對象-->
    <bean class="com.dpb.factoryprocessor.MyBeanFactoryPostProcessor"/>
</beans>      

8.測試

@Test
public void test1() {
    System.out.println("Spring容器開始加載....");
    ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
    User user = ac.getBean(User.class);
    System.out.println("---------------"+user);
    ac.registerShutdownHook();
    System.out.println("Spring容器解除安裝完成....");
}      

輸出結果

Spring容器開始加載....
三月 04, 2019 11:14:38 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
資訊: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@707f7052: startup date [Mon Mar 04 23:14:38 CST 2019]; root of context hierarchy
三月 04, 2019 11:14:39 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
資訊: Loading XML bean definitions from class path resource [applicationContext.xml]
****** BeanFactoryPostProcessor 開始執行了
******* BeanFactoryPostProcessor 執行結束了
【--InstantiationAwareBeanPostProcessor----】postProcessBeforeInstantiation
構造方法被執行了...User 被執行個體化
【--InstantiationAwareBeanPostProcessor----】postProcessAfterInstantiation
【--InstantiationAwareBeanPostProcessor----】postProcessPropertyValues--->
《注入屬性》注入name屬性波波烤鴨
【BeanNameWare接口】setBeanName
【BeanFactoryAware接口】setBeanFactory
>>後置處理器 before方法:User [id=0, name=波波烤鴨, beanName=user]  user
【---InstantiationAwareBeanPostProcessor---】 postProcessBeforeInitialization
初始化:【@PostConstruct】執行了...
初始化:《InitializingBean接口》afterPropertiesSet....
初始化:【init-method】方法執行了....
<<後置處理器after方法:User [id=0, name=波波烤鴨, beanName=user]    user
【--InstantiationAwareBeanPostProcessor----】 postProcessAfterInitialization
---------------User [id=0, name=波波烤鴨, beanName=user]
Spring容器解除安裝完成....
三月 04, 2019 11:14:39 下午 org.springframework.context.support.ClassPathXmlApplicationContext doClose
資訊: Closing org.springframework.context.support.ClassPathXmlApplicationContext@707f7052: startup date [Mon Mar 04 23:14:38 CST 2019]; root of context hierarchy
【@preDestory】執行了...
《DisposableBean接口》destroy ....
【destory-method】方法執行了....      

四、Bean對象生命周期總結

   如果實作了BeanFactoryPostProcessor接口,那麼在容器啟動的時候,該接口中的postProcessBeanFactory方法可以修改Bean中中繼資料中的資訊。該方法是在執行個體化對象之前執行

   如果實作了InstantiationAwareBeanPostProcessor接口,那麼在執行個體化Bean對象之前會調用postProcessBeforeInstantiation方法,該方法如果傳回的不為null則會直接調用postProcessAfterInitialization方法,而跳過了Bean執行個體化後及初始化前的相關方法,如果傳回null則正常流程,postProcessAfterInstantiation在執行個體化成功後執行,這個時候對象已經被執行個體化,但是該執行個體的屬性還未被設定,都是null。因為它的傳回值是決定要不要調用postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法傳回false,并且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果傳回true, postProcessPropertyValues就會被執行,postProcessPropertyValues用來修改屬性,在初始化方法之前執行。

   如果實作了Aware相關的結果,那麼相關的set方法會在初始化之前執行。

   如果實作了BeanPostProcessor接口,那麼該接口的方法會在執行個體化後的初始化方法前後執行。

   如果實作了InitializingBean接口則在初始化的時候執行afterPropertiesSet

   如果指定了init-method屬性則在初始化的時候會執行指定的方法。

   如果指定了@PostConstruct則在初始化的時候會執行标注的方法。

   到此對象建立完成

   當對象需要銷毀的時候。

   如果實作了DisposableBean接口會執行destroy方法

   如果指定了destroy-method屬性則會執行指定的方法

   如果指定了@PreDestroy注解則會執行标注的方法

~ 這就是Bean對象的生命周期了。有問題的歡迎留言