1. Bean 的生命周期概述

区别于一般的 Java 目标需求经过 new 创立目标,Spring 的 Bean 由 IoC 容器进行实例化、拼装以及办理的。也便是说 Bean 的生命周期完全由 IoC 容器控制

Spring 容器只能办理 单例(singleton) 效果域的 Bean 的完好生命周期,对于 原型(prototype) 效果域的 Bean,Spring 容器只创立 bean 的实例后便会回来给用户,剩下的生命周期由用户控制。所以 Bean 的生命周期主要指的是 singleton 效果域 的 Bean。

为什么要了解 Bean 的生命周期?

经过了解 Bean 的生命周期能够了解 Bean 是什么时候被创立的,什么时候初始化,什么时候被毁掉以及整个 Bean 的生命周期中哪些阶段能够运用哪些增加办法。

这样在实际开发中,能够使用 Bean 的生命周期的指定时间完结一些自定义的操作。一起面试中 Spring Bean 的生命周期也是常问的一个内容,所以很有必要了解一下。

Bean 的生命周期主要包括四个部分

  1. 实例化(Instantiation)
  2. 特点赋值(Populate)
  3. 初始化(Initialization)
  4. 毁掉(Destruction)

AbstractApplicationContextrefresh() 办法为进口,AbstractAutowireCapableBeanFactorydoCreateBean 办法完结对 Bean 的实例化、特点注入以及初始化。(详细流程能够看 3.2 的详细流程整理)

浅谈 Spring Bean 的生命周期

AbstractApplicationContextclose() 办法为进口,在 DisposableBeanAdapterdestory() 办法完结对 Bean 的毁掉。(详细流程能够看 3.2 的详细流程整理)

浅谈 Spring Bean 的生命周期


2. 相关接口及办法

Bean 的生命周期中运用到了 Aware 类型的相关接口、InitializingBean/DisposableBean 接口以及一些起到增强效果的接口。了解这些接口能够协助大家更好地了解 Bean 的生命周期以及更好地拓宽定制自己的 Bean 目标。

2.1 各种 Aware 类型的接口

完成 Aware 接口的目的是让程序能够拿到 Spring 容器的当时的运行环境(如当时 Bean 的称号、当时的 BeanFactory、当时的 ApplicationContext 等等资源)。这类接口的调用机遇是在 Bean 实例化、特点注入之后,初始化之前

接下来列出一些常用的子接口,有爱好的能够从源码中检查还有哪些接口(基本都是见名知意):

BeanNameAware 接口

接口中只要一个办法 void setBeanName(String name) 用于获取当时 Bean 的称号。

浅谈 Spring Bean 的生命周期

BeanFactoryAware 接口

接口中只要一个办法 void setBeanFactory(BeanFactory beanFactory) 用于获取当时的 BeanFactory。

浅谈 Spring Bean 的生命周期

ApplicationContextAware 接口

接口中只要一个办法 void setApplicationContext(ApplicationContext applicationContext) 用于获取当时的 ApplicationContext。

浅谈 Spring Bean 的生命周期


2.2 InitializingBean/DisposableBean 接口

完成InitializingBean/DisposableBean 接口能够完成自定义初始化办法以及毁掉办法。这两个接口的调用机遇分别在初始化阶段与毁掉阶段

InitializingBean 接口

接口中只要一个办法 void afterPropertiesSet() 用于自定义初始化行为,在特点注入阶段后履行。

浅谈 Spring Bean 的生命周期

DisposableBean 接口

接口中只要一个办法 void destroy() 用于自定义毁掉行为,在毁掉阶段履行。

浅谈 Spring Bean 的生命周期

除了接口完成办法外,还有两种能够完成自定义初始化以及毁掉的办法:

  • 运用 XML 装备文件 或许 Java 装备类 对 Bean 中的 init-methoddestroy-method 特点进行装备(基于 Bean 本身的初始化和毁掉)
  • 运用 注解 @PostConstruct@PreDestroy 修饰办法(效果于servlet生命周期的注解)

2.3 增强办法

BeanFactoryPostProcessor 接口

完成该接口能够增强的方面是:在 BeanFactory 已经初始化而 Bean 实例化之前调用该接口的办法能够修正或增加 Bean 的定义。所以该接口的调用机遇是在 Bean 实例化之前

接口中只要一个办法 void postProcessBeanFactory(ConfigurableListableBeanFactory var1) 用于在 Bean 实例化之前修正 Bean 的定义。

浅谈 Spring Bean 的生命周期

BeanPostProcessor 接口

完成该接口能增强的方面是:在 Bean 实例化后,在初始化阶段的前后自定义行为。能够依据接口办法中的参数来挑选需求自定义行为的 Bean。该接口的调用机遇是在 初始化阶段的前后

该接口有两个办法分别在初始化前和初始化后履行:

  • postProcessBeforeInitialization(Object bean, String beanName):初始化前调用
  • postProcessAfterInitialization(Object bean, String beanName):初始化后调用

浅谈 Spring Bean 的生命周期

InstantiationAwareBeanPostProcessor 接口

完成该接口能增强的方面是:在目标 Bean 实例化的前后能够自定义行为以及在特点注入前能够修正 Bean 的特点设置。

该接口有三个办法(其实还有两个来自于继承 BeanPostProcessor 接口的办法):

  • postProcessBeforeInstantiation(Class<?> beanClass, String beanName):在 Bean 实例化之前调用
  • postProcessAfterInstantiation(Object bean, String beanName):在 Bean 实例化之后调用
  • postProcessProperties(PropertyValues pvs, Object bean, String beanName):在 Bean 实例化之后,特点注入之前调用

浅谈 Spring Bean 的生命周期


3. 浅谈生命周期的详细流程

3.1 经过例子展示详细流程

经过一个例子来表现 Bean 的生命周期 的详细流程以及相关接口对应的切入机遇

MyBean 类

/**
 * Bean目标
 * @author 单程车票
 */
public class MyBean implements InitializingBean, DisposableBean, BeanNameAware {
    private Integer id;
    public MyBean(Integer id) {
        this.id = id;
        System.out.println("进程3(实例化阶段中):调用结构办法,当时id为" + this.id + "(能够发现id此刻并不是装备文件的1001,而是增强办法修正后的1002)");
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
        System.out.println("进程6(特点注入阶段中):特点注入阶段,注入后id为" + this.id + "(能够发现id此刻并不是装备文件的1003,而是增强办法修正后的1004)");
    }
    @Override
    public void setBeanName(String name) {
        System.out.println("进程7(特点注入阶段后):获取当时Bean的称号:" + name);
    }
    public void myInit() {
        System.out.println("进程10(初始化阶段中):调用Bean本身特点 init-method 的初始化办法");
    }
    public void myDestroy() {
        System.out.println("进程13(毁掉阶段中):调用Bean本身特点 destroy-method 的毁掉办法");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("进程9(初始化阶段中):调用 InitializingBean接口 的初始化办法");
    }
    @Override
    public void destroy() throws Exception {
        System.out.println("进程12(毁掉阶段中):调用 DisposableBean接口 的毁掉办法");
    }
}

完成 BeanFactoryPostProcessor 接口

/**
 * 对实例化前进行增强
 * @author 单程车票
 */
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("myBean");
        ConstructorArgumentValues constructorArgumentValues = new ConstructorArgumentValues();
        constructorArgumentValues.addIndexedArgumentValue(0, 1002);
        // 将原本装备文件装备的值1001改为1002(这儿运用了ConstructorArgumentValues有爱好的能够自行了解一下)
        beanDefinition.setConstructorArgumentValues(constructorArgumentValues);
        System.out.println("进程1(实例化阶段前): 调用 BeanFactoryPostProcessor.postProcessBeanFactory 办法进行增强,将id值改为1002");
    }
}

完成 BeanPostProcessor 接口

/**
 * 对初始化阶段前后进行增强
 * @author 单程车票
 */
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if ("myBean".equals(beanName)) {
            System.out.println("进程8(特点注入阶段后,初始化阶段前):调用 BeanPostProcessor.postProcessBeforeInitialization 办法进行增强");
        }
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if ("myBean".equals(beanName)) {
            System.out.println("进程11(初始化阶段后):调用 BeanPostProcessor.postProcessAfterInitialization 办法进行增强");
        }
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}

完成 InstantiationAwareBeanPostProcessor 接口

/**
 * 完成InstantiationAwareBeanPostProcessor接口
 * @author 单程车票
 */
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if ("myBean".equals(beanName)) {
            System.out.println("进程2(实例化阶段前):调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation 办法进行增强");
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
    }
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if ("myBean".equals(beanName)) {
            System.out.println("进程4(实例化阶段后):调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation 办法进行增强");
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
    }
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if ("myBean".equals(beanName)) {  // 对 Bean 再次修正 id 特点
            PropertyValue propertyValue = pvs.getPropertyValue("id");
            assert propertyValue != null;
            propertyValue.setConvertedValue(1004);
            System.out.println("进程5(实例化阶段后,特点注入阶段前):调用 InstantiationAwareBeanPostProcessor.postProcessProperties 办法进行增强,将id特点改为1004");
        }
        return InstantiationAwareBeanPostProcessor.super.postProcessProperties(pvs, bean, beanName);
    }
}

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">
    <!-- 这儿需求留意加上 Bean本身的初始化办法和毁掉办法 -->
    <bean id="myBean" class="com.xqsr.springtest.bean.MyBean" init-method="myInit" destroy-method="myDestroy">
        <!-- 这儿需求留意结构器(实例化)的id值为1001 -->
        <constructor-arg name="id" value="1001"/>
        <!-- 这儿需求留意setter(特点注入)的id值为1001 -->
        <property name="id" value="1003"/>
    </bean>
    <bean class="com.xqsr.springtest.bean.MyBeanFactoryPostProcessor"/>
    <bean class="com.xqsr.springtest.bean.MyBeanPostProcessor"/>
    <bean class="com.xqsr.springtest.bean.MyInstantiationAwareBeanPostProcessor"/>
</beans>

测验类

/**
 * 测验类
 * @author 单程车票
 */
public class Application {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        MyBean bean = (MyBean) applicationContext.getBean("myBean");
        ((AbstractApplicationContext) applicationContext).close();
    }
}

履行成果

浅谈 Spring Bean 的生命周期


3.2 详细流程整理

经过上面的例子能够整理出下面这张 Bean 的生命周期 详细流程图

浅谈 Spring Bean 的生命周期

接下来从源码的角度对流程图的每一个部分进行分析

从源码看 BeanFactoryPostProcessor # postProcessBeanFactory() 在实例化前履行

浅谈 Spring Bean 的生命周期

浅谈 Spring Bean 的生命周期

经过从 refresh() 进口进入依照上面图中的流程能够找到调用 postProcessBeanFactory() 的办法,该办法是在 invokeBeanFactoryPostProcessors(beanFactory) 进入的,而实例化阶段是从 finishBeanFactoryInitialization(beanFactory) 进入的,所以能够阐明 BeanFactoryPostProcessor # postProcessBeanFactory() 要先于实例化履行。

浅谈 Spring Bean 的生命周期


从源码看 InstantiationAwareBeanPostProcessor # postProcessBeforeInstantiation() 在实例化前履行

浅谈 Spring Bean 的生命周期

浅谈 Spring Bean 的生命周期

经过上面的流程图能够找到调用 postProcessBeforeInstantiation() 的办法是在 resolveBeforeInstantiation(beanName, mbdToUse) 进入的,而实例化阶段是在 doCreateBean(beanName, mbdToUse, args) 进入的,所以能够阐明 postProcessBeforeInstantiation() 要先于实例化履行。

浅谈 Spring Bean 的生命周期


从源码看 实例化履行方位 与 特点注入履行方位

浅谈 Spring Bean 的生命周期

实例化阶段发生在 AbstractAutowireCapableBeanFactorycreateBeanInstance() 办法中。

特点注入阶段发生在 AbstractAutowireCapableBeanFactorypopulateBean() 办法中。

浅谈 Spring Bean 的生命周期


从源码看 InstantiationAwareBeanPostProcessor # postProcessAfterInstantiation()InstantiationAwareBeanPostProcessor # postProcessPropertyValues() 特点注入阶段前履行

浅谈 Spring Bean 的生命周期

经过上面的流程图能够找到 postProcessAfterInstantiation()postProcessPropertyValues()populateBean() 特点注入办法内被调用。

浅谈 Spring Bean 的生命周期

  • postProcessAfterInstantiation() 办法假如找到指定的 bean 就会回来 false,会直接回来不再履行后续办法内容,也便是说后续的特点填充和依赖注入就不会被履行,所以能够看出 postProcessAfterInstantiation() 履行在特点注入阶段前。
  • postProcessPropertyValues() 办法相同发生在 特点填充 之前,假如回来null则不会履行后续的特点填充,假如不会为null,阐明有额定增加的特点需求填充,后续办法会履行特点填充。

从源码看 初始化阶段及其前后发生的调用

浅谈 Spring Bean 的生命周期

依据上面的流程图能够找到初始化阶段进入的进口 initializeBean() 办法,详细代码如下图:

浅谈 Spring Bean 的生命周期

  1. 先看 Aware 接口的调用

    浅谈 Spring Bean 的生命周期
    除了上面 BeanXXXAware 接口的调用,如 ApplicationContextAware 接口的调用是发生在 applyBeanPostProcessorsBeforeInitialization 办法中的,也便是是经过 BeanPostProcessor的postProcessBeforeInitialization() 完成调用的,详细的能够自己跟一下源码。
    浅谈 Spring Bean 的生命周期

  2. BeanPostProcessor 的两个完成办法

    这两个完成办法分别经过 applyBeanPostProcessorsBeforeInitializationapplyBeanPostProcessorsAfterInitialization 办法调用,也能够看出一个在初始化前一个在初始化后履行。

    浅谈 Spring Bean 的生命周期
    浅谈 Spring Bean 的生命周期

  3. invokeInitMethods 初始化办法

    invokeInitMethods 初始化办法中调用了 InitializingBean 的自定义初始化办法 与 Bean本身特点中的 init-method 指定的办法。

    浅谈 Spring Bean 的生命周期


从源码看 毁掉阶段

浅谈 Spring Bean 的生命周期

依据上面的流程图最终会找到 DisposableBeanAdapterdestory() 办法,详细代码如下:

浅谈 Spring Bean 的生命周期

经过 destory() 办法也能够看到 毁掉阶段 先履行 DisposableBean 的毁掉办法,再履行 Bean 本身特点 destory-method 指定的办法。