Skip to content

Spring Bean 生命周期

在传统的 Java 应用中,Bean 的生命周期很简单,使用 Java 关键字 new 进行 Bean 的实例化后,这个 Bean 就可以使用了。一旦这个 Bean 长期不被使用,Java 自动进行垃圾回收。

相比之下,Spring 中 Bean 的生命周期较复杂,大致可以分为以下 5 个阶段:

  1. Bean 的实例化
  2. Bean 属性赋值
  3. Bean 的初始化
  4. Bean 的使用
  5. Bean 的销毁

Spring 根据 Bean 的作用域来选择 Bean 的管理方式,

  • 对于 singleton 作用域的 Bean 来说,Spring IoC 容器能够精确地控制 Bean 何时被创建、何时初始化完成以及何时被销毁;
  • 对于 prototype 作用域的 Bean 来说,Spring IoC 容器只负责创建,然后就将 Bean 的实例交给客户端代码管理,Spring IoC 容器将不再跟踪其生命周期。

Spring 生命周期流程

Spring Bean 的完整生命周期从创建 Spring IoC 容器开始,直到最终 Spring IoC 容器销毁 Bean 为止,其具体流程如下图所示。

Spring 生命周期流程
图1:Spring Bean 生命周期流程

Bean 生命周期的整个执行过程描述如下。

  1. Spring 启动,查找并加载需要被 Spring 管理的 Bean,对 Bean 进行实例化。
  2. 对 Bean 进行属性注入。
  3. 如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
  4. 如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
  5. 如果 Bean 实现了 ApplicationContextAware 接口,则 Spring 调用 setApplicationContext() 方法传入当前 ApplicationContext 实例的引用。
  6. 如果 Bean 实现了 BeanPostProcessor 接口,则 Spring 调用该接口的预初始化方法 postProcessBeforeInitialzation() 对 Bean 进行加工操作,此处非常重要,Spring 的 AOP 就是利用它实现的。
  7. 如果 Bean 实现了 InitializingBean 接口,则 Spring 将调用 afterPropertiesSet() 方法。
  8. 如果在配置文件中通过 init-method 属性指定了初始化方法,则调用该初始化方法。
  9. 如果 BeanPostProcessor 和 Bean 关联,则 Spring 将调用该接口的初始化方法 postProcessAfterInitialization()。此时,Bean 已经可以被应用系统使用了。
  10. 如果在 <bean> 中指定了该 Bean 的作用域为 singleton,则将该 Bean 放入 Spring IoC 的缓存池中,触发 Spring 对该 Bean 的生命周期管理;如果在 <bean> 中指定了该 Bean 的作用域为 prototype,则将该 Bean 交给调用者,调用者管理该 Bean 的生命周期,Spring 不再管理该 Bean。
  11. 如果 Bean 实现了 DisposableBean 接口,则 Spring 会调用 destory() 方法销毁 Bean;如果在配置文件中通过 destory-method 属性指定了 Bean 的销毁方法,则 Spring 将调用该方法对 Bean 进行销毁。

自定义 Bean 的生命周期

我们可以在 Spring Bean 生命周期的某个特定时刻,指定一些生命周期回调方法完成一些自定义的操作,对 Bean 的生命周期进行管理。

Bean 的生命周期回调方法主要有两种:

  • 初始化回调方法:在 Spring Bean 被初始化后调用,执行一些自定义的回调操作。
  • 销毁回调方法:在 Spring Bean 被销毁前调用,执行一些自定义的回调操作。

我们可以通过以下 3 种方式自定义 Bean 的生命周期回调方法:

  • 通过接口实现
  • 通过 XML 配置实现
  • 使用注解实现

如果一个 Bean 中有多种生命周期回调方法时,优先级顺序为:注解 > 接口 > XML 配置。

通过接口实现

我们可以在 Spring Bean 的 Java 类中,通过实现 InitializingBean 和 DisposableBean 接口,指定 Bean 的生命周期回调方法。

回调方式接口方法说明
初始化回调InitializingBeanafterPropertiesSet()指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
销毁回调DisposableBeandestroy()指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

注意:通常情况下,我们不建议通过这种方式指定生命周期回调方法,这是由于这种方式会导致代码的耦合性过高。

示例

下面我们就通过一个实例,来演示下如何通过接口指定 Bean 的生命周期回调方法。

  1. 参考《第一个 Spring 程序》,新建一个名为 spring-life-cycle-demo 的 Java 项目。

  2. 在 net.biancheng.c 包下,创建一个名为 LifeCycleBean 的 Java 类,代码如下。

java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
/***
* 使用接口,实现初始化回调 和销毁回调
*/
public class LifeCycleBean implements InitializingBean, DisposableBean {
    private static final Log LOGGER = LogFactory.getLog(LifeCycleBean.class);
    //网站名称
    private String webName;
    //网站地址
    private String url;
    public void setWebName(String webName) {
        this.webName = webName;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    @Override
    public String toString() {
        return "LifeCycleBean{" +
                "webName='" + webName + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
    /**
     * 初始化回调逻辑
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        LOGGER.info(" 调用接口:InitializingBean,方法:afterPropertiesSet,无参数");
    }
    /**
     * 销毁回调逻辑
     *
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        LOGGER.info(" 调用接口:DisposableBean,方法:destroy,无参数");
    }
}
  1. 在 src 目录下创建 Spring 配置文件 Beans.xml,配置如下。
xml
<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-3.0.xsd">
    <bean id="lifeCycleBean" class="net.biancheng.c.LifeCycleBean">
        <property name="webName" value="C语言中文网"></property>
        <property name="url" value="c.biancheng.net"></property>
    </bean>
</beans>
  1. 在 net.biancheng.c 包下,创建一个名为 MainApp 的类,代码如下。
java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);
    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
        LOGGER.info(lifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}

5. 运行 MainApp 类中的 main() 方法,控制台输出如下。

十二月 21, 2021 6:01:53 下午 net.biancheng.c.LifeCycleBean afterPropertiesSet
信息:  调用接口:InitializingBean,方法:afterPropertiesSet,无参数
十二月 21, 2021 6:01:53 下午 net.biancheng.c.MainApp main
信息: LifeCycleBean{webName='C语言中文网', url='c.biancheng.net'}
十二月 21, 2021 6:01:53 下午 net.biancheng.c.LifeCycleBean destroy
信息:  调用接口:DisposableBean,方法:destroy,无参数

通过 XML 配置实现

我们还可以在 Spring 的 XML 配置中,通过 <bean> 元素中的 init-method 和 destory-method 属性,指定 Bean 的生命周期回调方法。

XML 配置属性描述
init-method指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
destory-method指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

示例

下面我们通过一个实例,演示下如何通过 XML 配置指定 Bean 的生命周期回调方法。

  1. 参考《第一个 Spring 程序》,新建一个名为 spring-life-cycle-demo2 的 Java 项目。

  2. 在 net.biancheng.c 包下,创建一个名为 XMLLifeCycleBean 的 Java 类,代码如下。

java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 通过 XML 配置指定生命周期回调方法
*/
public class XMLLifeCycleBean {
    private static final Log LOGGER = LogFactory.getLog(XMLLifeCycleBean.class);
    //网站名称
    private String webName;
    //网站地址
    private String url;
    public void setWebName(String webName) {
        this.webName = webName;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    @Override
    public String toString() {
        return "XMLLifeCycleBean{" +
                "webName='" + webName + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
    /**
     * 初始化回调方法
     */
    public void init() {
        LOGGER.info("在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法");
    }
    /**
     * 销毁回调方法
     */
    public void destroy() {
        LOGGER.info("在 XML 配置中通过 destroy-method 属性指定回调方法:destroy() 方法");
    }
}
  1. 在 src 目录下,创建一个 Spring 配置文件 Beans.xml,配置内容如下。
xml
<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-3.0.xsd">
    <!--通过 XML 配置指定生命周期回调方法-->
    <bean id="xmlLifeCycleBean" class="net.biancheng.c.XMLLifeCycleBean" init-method="init" destroy-method="destroy">
        <property name="webName" value="C语言中文网2"></property>
        <property name="url" value="c.biancheng.net"></property>
    </bean>
</beans>
  1. 在 net.biancheng.c 包下,创建一个名为 MainApp 的 Java 类,代码如下。
java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);
    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        XMLLifeCycleBean xmlLifeCycleBean = context.getBean("xmlLifeCycleBean", XMLLifeCycleBean.class);
        LOGGER.info(xmlLifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}
  1. 执行 MainApp 中的 main() 方法,控制台输出如下。
十二月 22, 2021 10:12:35 上午 net.biancheng.c.XMLLifeCycleBean init
信息: 在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法
十二月 22, 2021 10:12:35 上午 net.biancheng.c.MainApp main
信息: XMLLifeCycleBean{webName='C语言中文网2', url='c.biancheng.net'}
十二月 22, 2021 10:12:35 上午 net.biancheng.c.XMLLifeCycleBean destroy
信息: 在 XML 配置中通过 destroy-method 属性指定销毁方法:destroy() 方法

使用注解实现

我们还可以通过 JSR-250 的 @PostConstruct 和 @PreDestroy 注解,指定 Bean 的生命周期回调方法。

注解描述
@PostConstruct指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。
@PreDestroy指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

示例

下面我们通过一个实例,演示下如何通过注解指定 Bean 的生命周期回调方法。

  1. 参考《第一个 Spring 程序》,新建一个名为 spring-life-cycle-demo3 的 Java 项目。

  2. 在 net.biancheng.c 包下,创建一个名为 AnnotationLifeCycleBean 的 Java 类,代码如下。

java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* 通过注解指定生命周期回调方法
*/
public class AnnotationLifeCycleBean {
    private static final Log LOGGER = LogFactory.getLog(AnnotationLifeCycleBean.class);
    //网站名称
    private String webName;
    //网站地址
    private String url;
    public AnnotationLifeCycleBean(String webName, String url) {
        this.webName = webName;
        this.url = url;
    }
    @Override
    public String toString() {
        return "AnnotationLifeCycleBean{" +
                "webName='" + webName + '\'' +
                ", url='" + url + '\'' +
                '}';
    }
    /**
     * 初始化回调方法
     */
    @PostConstruct
    public void init() {
        LOGGER.info("通过 @PostConstruct 注解,指定初始化方法:init() 方法");
    }
    /**
     * 销毁回调方法
     */
    @PreDestroy
    public void destroy() {
        LOGGER.info("通过 @PreDestroy 注解,指定初始化方法:destroy() 方法");
    }
}
  1. 在 src 目录下,新建一个 Spring 配置文件 Beans.xml,配置内容如下。
xml
<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-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--注解扫描-->
    <context:component-scan base-package="net.biancheng.c"></context:component-scan>
    <!--通过 XML 配置指定生命周期回调方法-->
    <bean id="annotationLifeCycleBean" class="net.biancheng.c.AnnotationLifeCycleBean">
        <constructor-arg name="webName" value="C语言中文网3"></constructor-arg>
        <constructor-arg name="url" value="c.biancheng.net"></constructor-arg>
    </bean>
</beans>
  1. 在 net.biancheng.c 包下,创建一个名为 MainApp 的 Java 类,代码如下。
java
package net.biancheng.c;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);
    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        AnnotationLifeCycleBean annotationLifeCycleBean = context.getBean("annotationLifeCycleBean", AnnotationLifeCycleBean.class);
        LOGGER.info(annotationLifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}
  1. 执行 MainApp 中的 main 函数,控制台输出如下。
十二月 22, 2021 11:06:14 上午 net.biancheng.c.AnnotationLifeCycleBean init
信息: 通过 @PostConstruct 注解,指定初始化方法:init() 方法
十二月 22, 2021 11:06:14 上午 net.biancheng.c.MainApp main
信息: AnnotationLifeCycleBean{webName='C语言中文网3', url='c.biancheng.net'}
十二月 22, 2021 11:06:14 上午 net.biancheng.c.AnnotationLifeCycleBean destroy
信息: 通过 @PreDestroy 注解,指定初始化方法:destroy() 方法