9.2 自定义 Bean 的生命周期

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

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

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

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

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

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

1. 通过接口实现

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

回调方式

接口

方法

说明

初始化回调

InitializingBean

afterPropertiesSet()

指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。

销毁回调

DisposableBean

destroy()

指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

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

例 1

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

创建命名为 LifeCycleBean 的类,代码如下:

package section2.demo1;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

/**
 * ClassName: LifeCycleBean
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class LifeCycleBean implements InitializingBean, DisposableBean {
    private static final Log LOGGER = LogFactory.getLog(LifeCycleBean.class);
    // 网站名称
    private String site;
    // 网站地址
    private String url;

    public void setSite(String site) {
        this.site = site;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "LifeCycleBean{" +
                "site='" + site + '\'' +
                ", 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,无参数");
    }
}

修改 Spring 配置文件 spring-config.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 id="lifeCycleBean" class="section2.demo1.LifeCycleBean">
        <property name="site" value="传陆编程"/>
        <property name="url" value="http://localhost"/>
    </bean>

</beans>

创建命名为 MainApp 的类,代码如下:

package section2.demo1;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * ClassName: MainApp
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);

    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        LifeCycleBean lifeCycleBean = context.getBean("lifeCycleBean", LifeCycleBean.class);
        LOGGER.info(lifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}

执行 MainApp 中的 main 方法,控制台输出如下:

4月 08, 2022 1:04:15 下午 section2.demo1.LifeCycleBean afterPropertiesSet
信息:  调用接口:InitializingBean,方法:afterPropertiesSet,无参数
4月 08, 2022 1:04:15 下午 section2.demo1.MainApp main
信息: LifeCycleBean{site='传陆编程', url='http://localhost'}
4月 08, 2022 1:04:15 下午 section2.demo1.LifeCycleBean destroy
信息:  调用接口:DisposableBean,方法:destroy,无参数

2. 通过 XML 配置实现

我们还可以在 Spring 的 XML 配置中,通过 <bean> 元素中的 init-methoddestory-method

XML 配置属性

描述

init-method

指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。

destory-method

指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

例 2

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

创建命名为 XMLLifeCycleBean 的 Java 类,代码如下:

package section2.demo2;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * ClassName: XMLLifeCycleBean
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class XMLLifeCycleBean {
    private static final Log LOGGER = LogFactory.getLog(XMLLifeCycleBean.class);
    // 网站名称
    private String site;
    // 网站地址
    private String url;

    public void setSite(String site) {
        this.site = site;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "XMLLifeCycleBean{" +
                "site='" + site + '\'' +
                ", url='" + url + '\'' +
                '}';
    }

    /**
     * 初始化回调方法
     */
    public void init() {
        LOGGER.info("在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法");
    }

    /**
     * 销毁回调方法
     */
    public void destroy() {
        LOGGER.info("在 XML 配置中通过 destroy-method 属性指定回调方法:destroy() 方法");
    }
}

修改 Spring 配置文件 spring-config.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">

    <!--通过 XML 配置指定生命周期回调方法-->
    <bean id="xmlLifeCycleBean" class="section2.demo2.XMLLifeCycleBean" init-method="init" destroy-method="destroy">
        <property name="site" value="传陆编程"/>
        <property name="url" value="http://localhost"/>
    </bean>

</beans>

创建命名为 MainApp 的类,代码如下:

package section2.demo2;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * ClassName: MainApp
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);

    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        XMLLifeCycleBean xmlLifeCycleBean = context.getBean("xmlLifeCycleBean", XMLLifeCycleBean.class);
        LOGGER.info(xmlLifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}

执行 MainApp 中的 main 方法,控制台输出如下:

4月 07, 2022 7:53:18 下午 section3.demo2.XMLLifeCycleBean init
信息: 在 XML 配置中通过 init-method 属性指定初始化方法:init() 方法
4月 07, 2022 7:53:18 下午 section3.demo2.MainApp main
信息: XMLLifeCycleBean{site='传陆编程', url='http://localhost'}
4月 07, 2022 7:53:18 下午 section3.demo2.XMLLifeCycleBean destroy
信息: 在 XML 配置中通过 destroy-method 属性指定回调方法:destroy() 方法

3. 使用注解实现

我们还可以通过 JSR-250 的 @PostConstruct@PreDestroy

注解

描述

@PostConstruct

指定初始化回调方法,这个方法会在 Spring Bean 被初始化后被调用,执行一些自定义的回调操作。

@PreDestroy

指定销毁回调方法,这个方法会在 Spring Bean 被销毁前被调用,执行一些自定义的回调操作。

例 3

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

创建命名为 AnnotationLifeCycleBean 的 Java 类,代码如下:

package section2.demo3;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * ClassName: AnnotationLifeCycleBean
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class AnnotationLifeCycleBean {
    private static final Log LOGGER = LogFactory.getLog(AnnotationLifeCycleBean.class);
    // 网站名称
    private String site;
    // 网站地址
    private String url;

    public void setSite(String site) {
        this.site = site;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    @Override
    public String toString() {
        return "XMLLifeCycleBean{" +
                "site='" + site + '\'' +
                ", url='" + url + '\'' +
                '}';
    }

    /**
     * 初始化回调方法
     */
    @PostConstruct
    public void init() {
        LOGGER.info("通过注解 @PostConstruct 调用指定初始化回调方法:init() 方法");
    }

    /**
     * 销毁回调方法
     */
    @PreDestroy
    public void destroy() {
        LOGGER.info("通过注解 @PreDestroy 调用指定销毁回调方法:destroy() 方法");
    }
}

修改 Spring 配置文件 spring-config.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"
       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.xsd">

    <!--注解扫描-->
    <context:component-scan base-package="section3.demo3"/>
    <!--通过注解指定生命周期回调方法-->
    <bean id="annotationLifeCycleBean" class="section3.demo3.AnnotationLifeCycleBean">
        <property name="site" value="传陆编程"/>
        <property name="url" value="http://localhost"/>
    </bean>
    
</beans>

创建命名为 MainApp 的类,代码如下:

package section2.demo3;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * ClassName: MainApp
 * Description: TODO
 *
 * @author chuanlu
 * @version 1.0.0
 */
public class MainApp {
    private static final Log LOGGER = LogFactory.getLog(MainApp.class);

    public static void main(String[] args) {
        //获取 ClassPathXmlApplicationContext 容器
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
        AnnotationLifeCycleBean annotationLifeCycleBean = context.getBean("annotationLifeCycleBean", AnnotationLifeCycleBean.class);
        LOGGER.info(annotationLifeCycleBean);
        //手动销毁 Bean
        context.close();
    }
}

执行 MainApp 中的 main 方法,控制台输出如下:

4月 08, 2022 1:30:06 下午 section2.demo3.AnnotationLifeCycleBean init
信息: 通过注解 @PostConstruct 调用指定初始化回调方法:init() 方法
4月 08, 2022 1:30:06 下午 section2.demo3.MainApp main
信息: XMLLifeCycleBean{site='传陆编程', url='http://localhost'}
4月 08, 2022 1:30:06 下午 section2.demo3.AnnotationLifeCycleBean destroy
信息: 通过注解 @PreDestroy 调用指定销毁回调方法:destroy() 方法

注意:这里需要依赖 jsr250-api-1.0.jar 这个 jar 包,本课程已经把它放在了 Spring-5.3.18 目录里