zoukankan      html  css  js  c++  java
  • 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+"	"+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+"	"+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对象生命周期总结

    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. 如果实现了InitializingBean接口则在初始化的时候执行afterPropertiesSet
    6. 如果指定了init-method属性则在初始化的时候会执行指定的方法。
    7. 如果指定了@PostConstruct则在初始化的时候会执行标注的方法。
    8. 到此对象创建完成
    9. 当对象需要销毁的时候。
    10. 如果实现了DisposableBean接口会执行destroy方法
    11. 如果指定了destory-method属性则会执行指定的方法
    12. 如果指定了@PreDestroy注解则会执行标注的方法

    ~ 这就是Bean对象的生命周期了。有问题的欢迎留言

  • 相关阅读:
    win7游戏窗口设置
    怎么在 html 中 动态的加载一个 script
    nodejs+express +jade模板引擎 新建项目
    将大数据利用 BCP 导出SqlServer数据到CSV
    产品经理如何赢得开发人员的尊重和支持?-摘自infoq
    Microsoft TFS 如何显示在Windows 的上下文菜单中
    使用PowerDesigner 设计SQL Server 数据库
    sqlserver 删掉日志文件ldf以后 救命语句
    SqlServer修改数据库文件及日志文件存放位置
    快速备份sqlserver2005以上版本数据库的方法-摘自网络
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/10474842.html
Copyright © 2011-2022 走看看