Spring之Bean的生命週期

阿木俠發表於2017-05-16

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物件生命週期總結

  1. 如果實現了BeanFactoryPostProcessor介面,那麼在容器啟動的時候,該介面中的postProcessBeanFactory方法可以修改Bean中後設資料中的資訊。該方法是在例項化物件之前執行
  2. 如果實現了InstantiationAwareBeanPostProcessor介面,那麼在例項化Bean物件之前會呼叫postProcessBeforeInstantiation方法,該方法如果返回的不為null則會直接呼叫postProcessAfterInitialization方法,而跳過了Bean例項化後及初始化前的相關方法,如果返回null則正常流程,postProcessAfterInstantiation在例項化成功後執行,這個時候物件已經被例項化,但是該例項的屬性還未被設定,都是null。因為它的返回值是決定要不要呼叫postProcessPropertyValues方法的其中一個因素(因為還有一個因素是mbd.getDependencyCheck());如果該方法返回false,並且不需要check,那麼postProcessPropertyValues就會被忽略不執行;如果返回true, postProcessPropertyValues就會被執行,postProcessPropertyValues用來修改屬性,在初始化方法之前執行。
  3. 如果實現了Aware相關的結果,那麼相關的set方法會在初始化之前執行。
  4. 如果實現了BeanPostProcessor介面,那麼該介面的方法會在例項化後的初始化方法5. 前後執行。
  5. 如果實現了InitializingBean介面則在初始化的時候執行afterPropertiesSet
  6. 如果指定了init-method屬性則在初始化的時候會執行指定的方法。
  7. 如果指定了@PostConstruct則在初始化的時候會執行標註的方法。 到此物件建立完成 當物件需要銷燬的時候。
  8. 如果實現了DisposableBean介面會執行destroy方法
  9. 如果指定了destroy-method屬性則會執行指定的方法
  10. 如果指定了@PreDestroy註解則會執行標註的方法

~ 這就是Bean物件的生命週期了。有問題的歡迎留言

相關文章