Spring之Bean的生命周期详解
通过前面多个接口的介绍了解了Bean对象生命周期相关的方法,本文就将这些接口的方法串起来,来了解Bean的完整的生命周期。而介绍Bean的生命周期也是面试过程中经常会碰到的一个问题,如果不注意就跳坑里啦~~
Spring之Bean对象的初始化和销毁方法
Spring之InitializingBean接口和DisposableBean接口介绍
Spring之Aware接口介绍
Spring之InstantiationAwareBeanPostProcessor接口介绍
Spring之BeanFactoryPostProcessor接口介绍
Spring之BeanPostProcessor(后置处理器)介绍
建议:看此文前请将上面相关的内容熟悉下,便于理解下面的内容。
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,destory-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接口》destory ....
【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方法
- 如果指定了destory-method属性则会执行指定的方法
- 如果指定了@PreDestroy注解则会执行标注的方法
~ 这就是Bean对象的生命周期了。有问题的欢迎留言
Spring之Bean的生命周期详解的更多相关文章
- Spring bean的生命周期详解
		bean的生命周期1.实例化bean 即new2.按照spring上下文对实例化的bean进行配置 即填充属性,也就是IOC/DI(控制反转,依赖注入)3.如果这个bean实现了BeanNameAwa ... 
- Spring Bean的生命周期详解(转)
		Spring作为当前Java最流行.最强大的轻量级框架,受到了程序员的热烈欢迎.准确的了解Spring Bean的生命周期是非常必要的.我们通常使用ApplicationContext作为Spring ... 
- Spring生命周期详解
		导读 Spring中Bean的生命周期从容器的启动到停止,涉及到的源码主要是在org.springframework.context.support.AbstractApplicationContex ... 
- ASP.NT运行原理和页面生命周期详解及其应用
		ASP.NT运行原理和页面生命周期详解及其应用 1. 下面是我画的一张关于asp.net运行原理和页面生命周期的一张详解图.如果你对具体不太了解,请参照博客园其他帖子.在这里我主要讲解它的实际应用. ... 
- JAVA面试题:Spring中bean的生命周期
		Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一 ... 
- ASP.NET生命周期详解
		最近一直在学习ASP.NET MVC的生命周期,发现ASP.NET MVC是建立在ASP.NET Framework基础之上的,所以原来对于ASP.NET WebForm中的很多处理流程,如管道事件等 ... 
- ASP.NET生命周期详解 [转]
		最近一直在学习ASP.NET MVC的生命周期,发现ASP.NET MVC是建立在ASP.NET Framework基础之上的,所以原来对于ASP.NET WebForm中的很多处理流程,如管道事件等 ... 
- 深入理解Spring中bean的生命周期
		[Spring中bean的生命周期] bean的生命周期 1.以ApplocationContext上下文单例模式装配bean为例,深入探讨bean的生命周期: (1).生命周期图: (2).具体事例 ... 
- Spring中Bean的生命周期及其扩展点
		原创作品,可以转载,但是请标注出处地址http://www.cnblogs.com/V1haoge/p/6106456.html Spring中Bean的管理是其最基本的功能,根据下面的图来了解Spr ... 
随机推荐
- ajax动态刷新的元素,导致绑定事件失效
			jquery事件绑定有2种方式: 1,普通事件绑定: $('元素').click(function(){}); 2, 事件代理或者叫事件委托 $('#chatPanelList').on('click ... 
- MySQL 多表结构的创建与分析
			=====================多对一===================== create table press( id int primary key auto_increment, ... 
- robotframework-databaselibrary安装步骤
			我这里主要介绍离线安装的方式 第一步:下载robotframework-databaselibrary-0.6 包可以去网上找安装包下载,如果实在找不到可以联系我 第二步:下载PyMySQL-0.9. ... 
- oracle RAC
			RAC安装步骤 1 配置共享存储 2 Grid Infrastructure软件的安装,GI主要用于cluster ,storage的管理 3 安装数据库软件 ... 
- zookeeper原理与安装
			Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目. 1. Zookerper工作机制 2. Zookeeper工作特点 3. Zookeeper文件系统: ... 
- DelphiXE10.2.3——跨平台生成验证码图片
			$("#img-code").bind( 'click', function () { $(this).attr('src','VerifyCode?t='+Math.random ... 
- Android X 相关汇总
			一.说明 官方原文如下: We hope the division between android.* and androidx.* makes it more obvious which APIs ... 
- genymotion常见问题解答
			[转]常见问题解答 很多人喜欢使用Genymotion这款安卓模拟器,但是虽然Genymotion很好用,可是却有各种问题存在哦,下面潇潇就一些常见的Genymotion问题来说下解决方法吧. 为什么 ... 
- puppet-type
			puppet语法-type Table of Contents Custom Source 基本技能要求 Types简介 Type-Documentation Type-Properties Type ... 
- Kali学习笔记8:四层发现
			1.基于TCP协议 优点: 1.可路由且结果可靠 2.不太可能会被防火墙过滤 3.甚至可以发现端口 缺点: 速度较慢(三次握手) 利用Scapy发送ACK数据包: 配置数据包: 发送数据包: 看一下收 ... 
