Spring Bean生命週期總結

1、簡要說明

1)本文基於spring5.1.7版本,採用ApplicationContext獲取bean對象。

2)BeanFactory和ApplicationContext對於bean後置處理器還有所不同,需要注意,ApplicationContext會自動檢測在配置文件中實現了BeanPostProcessor接口的所有bean,並把它們註冊爲後置處理器,然後在容器創建bean的適當時候調用它,因此部署一個後置處理器同部署其他的bean並沒有什麼區別。而使用BeanFactory實現的時候,bean 後置處理器必須通過代碼顯式地去註冊。

2、Bean的生命週期

2.1、生命週期流程圖
在這裏插入圖片描述
2.2、總體概述
我們知道一個對象的生命週期:創建(實例化-初始化)-使用-銷燬,而在Spring中,Bean對象週期當然遵從這一過程,但是Spring提供了許多對外接口,允許開發者對三個過程(實例化、初始化、銷燬)的前後做一些操作。
  這裏就實例化、初始化區別做一個說明,在Spring Bean中,實例化是爲bean對象開闢空間(具體可以理解爲構造函數的調用),初始化則是對屬性的初始化,說的具體點,這裏的屬性初始化應該是屬性的注入(構造函數也可以有屬性的初始化語句,但不屬於這一部分),屬性注入是通過setter方法注入屬性(不管是註解方式還是bean配置property屬性方式,其實質都是通過屬性的setter方法實現的)。
  
2.3、接口及方法介紹

Bean的完整生命週期經歷了各種方法調用,這些方法可以劃分爲以下幾類:

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

2)Bean級生命週期接口方法:BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這些接口的方法。每個Bean選擇實現,可選擇各自的個性化操作。

3、容器級生命週期接口方法:這個包括了InstantiationAwareBeanPostProcessor 和 BeanPostProcessor 這兩個接口實現(前者繼承自後者),一般稱它們的實現類爲“後處理器”。這些接口是每個bean實例化或初始化時候都會調用。

4、工廠後處理器接口方法:這些方法也是容器級別的,但它們是在上下文裝置配置文件之後調用,例如BeanFactoryPostProcessor、 CustomAutowireConfigurer等。

3、具體代碼實現

1)定義一個bean類(CustomBean)

它實現了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean這4個接口,同時有2個方法,對應配置文件中的init-method和destroy-method。

/**
 * @author xf
 * @description 自定義bean
 * @date 2019/5/22 11:52
 */
public class CustomBean implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean {

    private String name;
    private String address;

    private BeanFactory beanFactory;
    private String beanName;

    public CustomBean() {
        System.out.println("第6步:【構造器】調用CustomBean的構造器實例化");
    }

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

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

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

    // 通過spring的xml配置文件<bean>的init-method屬性指定的初始化方法
    public void xml_init() {
        System.out.println("第16步:【init-method】調用<bean>的init-method屬性指定的初始化方法");
    }

    // 通過spring的xml配置文件<bean>的destroy-method屬性指定的初始化方法
    public void xml_destroy() {
        System.out.println("第21步:【destroy-method】調用<bean>的destroy-method屬性指定的銷燬方法");
    }

    // 這是BeanFactoryAware接口方法
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out
                .println("第12步:【執行BeanFactoryAware接口的setBeanFactory方法】setBeanName後調用");
        this.beanFactory = beanFactory;
    }

    // 這是BeanNameAware接口方法
    @Override
    public void setBeanName(String s) {
        System.out.println("第11步:【執行BeanNameAware接口的setBeanName方法】屬性注入後調用, 此時s = "+s);
        this.beanName = s;
    }

    // 這是InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("第15步:【執行InitializingBean接口的afterPropertiesSet方法】在processBeforeInitialization之後,配置的xml_init之前調用");
    }

    // 這是DiposibleBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("第20步:【執行DiposibleBean接口的destroy方法】在processAfterInitialization之後,配置的xml_destroy之前調用");
    }
}

2)BeanFactoryPostProcessor類(工廠後處理器)

/**
 * @author xf
 * @description 工廠後處理器
 * @date 2019/5/22 14:05
 */
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    public CustomBeanFactoryPostProcessor() {
        System.out.println("第1步:這是BeanFactoryPostProcessor(工廠後處理器)實現類CustomBeanFactoryPostProcessor的構造器!!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        System.out.println("第2步:調用BeanFactoryPostProcessor(工廠後處理器)實現類CustomBeanFactoryPostProcessor的方法postProcessBeanFactory。ApplicationContext容器初始化中refresh()中調用");
    }
}

3)BeanPostProcessor類

/**
 * @author xf
 * @description BeanPostProcessor的實現類
 * @date 2019/5/22 14:06
 */
public class InitialBeanPostProcessor implements BeanPostProcessor {

    public InitialBeanPostProcessor() {
        System.out.println("第4步:這是BeanPostProcessor實現類(InitialBeanPostProcessor)的構造器!!");
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第14步:postProcessBeforeInitialization(BeanPostProcessor接口實現類InitialBeanPostProcessor的方法)對屬性進行更改, bean = " + bean.getClass());
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第18步:postProcessAfterInitialization(BeanPostProcessor接口的方法)對屬性進行更改, bean = " + bean.getClass());
        return bean;
    }
}

4)InstantiationAwareBeanPostProcessor 接口本質是BeanPostProcessor的子接口,一般我們繼承Spring爲其提供的適配器類InstantiationAwareBeanPostProcessor Adapter來使用它

/**
 * @author xf
 * @description 實例化處理器
 * @date 2019/5/22 14:12
 */
public class InstanceBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {

    public InstanceBeanPostProcessor() {
        System.out.println("第3步:這是InstantiationAwareBeanPostProcessorAdapter實現類(InstanceBeanPostProcessor)構造器!!");
    }

    //實例化bean之前調用
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        System.out.println("第5步:實例化"+beanClass.getName()+"之前調用,即調用"+beanClass.getName()+"類構造函數之前調用 ");
        return super.postProcessBeforeInstantiation(beanClass, beanName);
    }

    //實例化bean之後調用
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        System.out.println("第7步:返回boolean,bean實例化後調用,並且返回false則不會注入屬性");
        return super.postProcessAfterInstantiation(bean, beanName);
    }

    // 設置bean的某個屬性時調用
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        System.out.println("第8步:postProcessProperties,在屬性注入之前調用;beanName = " + beanName + ";屬性名集合 : " + Arrays.toString(pvs.getPropertyValues()));
        return super.postProcessProperties(pvs, bean, beanName);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第13步:postProcessBeforeInitialization(InstantiationAwareBeanPostProcessorAdapter實現類InstanceBeanPostProcessor的方法) ");
        return super.postProcessBeforeInitialization(bean, beanName);
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("第17步:postProcessAfterInitialization(InstantiationAwareBeanPostProcessorAdapter類的實現方法) ");
        return super.postProcessAfterInitialization(bean, beanName);
    }
}

5)Spring Bean的配置文件spring-bean.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"
	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.xsd">

	<bean id="beanFactoryPostProcessor" class="com.spring.springbeancycle.CustomBeanFactoryPostProcessor">
	</bean>
	<bean id="instantiationAwareBeanPostProcessor" class="com.spring.springbeancycle.InstanceBeanPostProcessor">
	</bean>
	<bean id="beanPostProcessor" class="com.spring.springbeancycle.InitialBeanPostProcessor">
	</bean>
	<bean id="customBean" class="com.spring.springbeancycle.CustomBean" init-method="xml_init" destroy-method="xml_destroy">
		<property name="name" value="小明"></property>
		<property name="address" value="天涯海角"></property>
	</bean>

</beans>

6)測試類

/**
 * @author xf
 * @description 測試類
 * @date 2019/5/22 14:23
 */
public class SpringBeanTest {
    public static void main(String[] args) {
        System.out.println("====現在開始初始化容器====");
        ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:spring-bean.xml");
        System.out.println("====容器初始化成功====");
        CustomBean customBean = (CustomBean)context.getBean("customBean");
        System.out.println("第19步:customBean = " + customBean);
        System.out.println("====現在開始關閉容器!====");
        ((ClassPathXmlApplicationContext)context).close();
    }
}

7)測試結果

第1步:這是BeanFactoryPostProcessor(工廠後處理器)實現類CustomBeanFactoryPostProcessor的構造器!!
第2步:調用BeanFactoryPostProcessor(工廠後處理器)實現類CustomBeanFactoryPostProcessor的方法postProcessBeanFactory。ApplicationContext容器初始化中refresh()中調用
第3步:這是InstantiationAwareBeanPostProcessorAdapter實現類(InstanceBeanPostProcessor)構造器!!
第4步:這是BeanPostProcessor實現類(InitialBeanPostProcessor)的構造器!!
第5步:實例化com.spring.springbeancycle.CustomBean之前調用,即調用com.spring.springbeancycle.CustomBean類構造函數之前調用 
第6步:【構造器】調用CustomBean的構造器實例化
第7步:返回boolean,bean實例化後調用,並且返回false則不會注入屬性
第8步:postProcessProperties,在屬性注入之前調用;beanName = customBean;屬性名集合 : [bean property 'name', bean property 'address']
第9步:【注入屬性】注入屬性name
第10步:【注入屬性】注入屬性address
第11步:【執行BeanNameAware接口的setBeanName方法】屬性注入後調用, 此時s = customBean
第12步:【執行BeanFactoryAware接口的setBeanFactory方法】setBeanName後調用
第13步:postProcessBeforeInitialization(InstantiationAwareBeanPostProcessorAdapter實現類InstanceBeanPostProcessor的方法) 
第14步:postProcessBeforeInitialization(BeanPostProcessor接口實現類InitialBeanPostProcessor的方法)對屬性進行更改, bean = class com.spring.springbeancycle.CustomBean
第15步:【執行InitializingBean接口的afterPropertiesSet方法】在processBeforeInitialization之後,配置的xml_init之前調用
第16步:【init-method】調用<bean>的init-method屬性指定的初始化方法
第17步:postProcessAfterInitialization(InstantiationAwareBeanPostProcessorAdapter類的實現方法) 
第18步:postProcessAfterInitialization(BeanPostProcessor接口的方法)對屬性進行更改, bean = class com.spring.springbeancycle.CustomBean
====容器初始化成功====
第19步:customBean = CustomBean{name='小明', address='天涯海角'}
====現在開始關閉容器!====
第20步:【執行DiposibleBean接口的destroy方法】在processAfterInitialization之後,配置的xml_destroy之前調用
第21步:【destroy-method】調用<bean>的destroy-method屬性指定的銷燬方法

4、流程總結

1、實例化一個Bean--也就是我們常說的new;

2、按照Spring上下文對實例化的Bean進行配置--也就是IOC注入;

3、如果這個Bean已經實現了BeanNameAware接口,會調用它實現的setBeanName(String)方法,此處傳遞的就是Spring配置文件中Bean的id值

4、如果這個Bean已經實現了BeanFactoryAware接口,會調用它實現的setBeanFactory(setBeanFactory(BeanFactory)傳遞的是Spring工廠自身(可以用這個方式來獲取其它Bean,只需在Spring配置文件中配置一個普通的Bean就可以);

5、如果這個Bean已經實現了ApplicationContextAware接口,會調用setApplicationContext(ApplicationContext)方法,傳入Spring上下文(同樣這個方式也可以實現步驟4的內容,但比4更好,因爲ApplicationContext是BeanFactory的子接口,有更多的實現方法);

6、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor經常被用作是Bean內容的更改,並且由於這個是在Bean初始化結束時調用那個的方法,也可以被應用於內存或緩存技術;

7、如果Bean在Spring配置文件中配置了init-method屬性會自動調用其配置的初始化方法。

8、如果這個Bean關聯了BeanPostProcessor接口,將會調用postProcessAfterInitialization(Object obj, String s)方法、;

注:以上工作完成以後就可以應用這個Bean了,那這個Bean是一個Singleton的,所以一般情況下我們調用同一個id的Bean會是在內容地址相同的實例,當然在Spring配置文件中也可以配置非Singleton,這裏我們不做贅述。

9、當Bean不再需要時,會經過清理階段,如果Bean實現了DisposableBean這個接口,會調用那個其實現的destroy()方法;

10、最後,如果這個Bean的Spring配置中配置了destroy-method屬性,會自動調用其配置的銷燬方法。

參考地址:
https://www.cnblogs.com/zrtqsk/p/3735273.html
https://uule.iteye.com/blog/2094609
https://blog.csdn.net/a327369238/article/details/52193822
https://www.cnblogs.com/kenshinobiy/p/4652008.html

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