• 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对象的生命周期了。有问题的欢迎留言

  • 相关阅读:
    Golang Failpoint 的设计与实现
    没涉及到最值求解;观点:矩阵乘法无法表达出结果。 现实生活中事件、现象的数学表达
    多元微分学 枚举破解15位路由器密码 存储空间限制 拆分减长,求最值 数据去重
    ARP Poisoning Attack and Mitigation Techniques ARP欺骗 中间人攻击 Man-In-The-Middle (MITM) attack 嗅探 防范 Can one MAC address have two different IP addresses within the network?
    The C10K problem
    HTTP Streaming Architecture HLS 直播点播 HTTP流架构
    现代IM系统中消息推送和存储架构的实现
    现代IM系统中的消息系统架构
    长连接锁服务优化实践 C10K问题 nodejs的内部构造 limits.conf文件修改 sysctl.conf文件修改
    doubleclick cookie、动态脚本、用户画像、用户行为分析和海量数据存取 推荐词 京东 电商 信息上传 黑洞 https://blackhole.m.jd.com/getinfo
  • 原文地址:https://www.cnblogs.com/dengpengbo/p/10474842.html
Copyright © 2020-2023  润新知