一、前言

  Lifecycle是Spring中最基础的生命周期接口,该接口定义了容器启动停止的方法。方便开发者扩展自己的特定逻辑,比如启动和停止某些后台进程。
  SmartLifecycle是对Lifecycle的一个扩展接口,当我们实现SmartLifecycle接口时,发现需要实现很多方法。很多同学不理解这些方法是干嘛的,今天我们来一起探讨下~

二、先说Lifecycle

  Lifecycle常用来管理一个组件的启动和停止,这个组件可以是一个线程、或者是一件事情。有同学可能会有这样的疑惑:开始和停止的逻辑写在一个bean的初始化方法和销毁方法中不可以了吗,为什么要实现个Lifecycle接口呢?这里说明一下,bean的初始化方法和销毁方法是Bean生命周期级别的;而Lifecycle是容器生命周期级别的。
我们来看下使用步骤~

1. 定义一个类并实现Lifecycle接口
public class MyLifecycle implements Lifecycle {
    /**
     * A 组件的运行状态
     */
    private volatile boolean running = false;

    /**
     * 容器启动后调用
     */
    @Override
    public void start() {
        System.out.println("lifecycle 容器启动完成,启动A组件...");
        running = true;
    }

    /**
     * 容器停止时调用
     */
    @Override
    public void stop() {
        System.out.println("lifecycle 收到关闭容器的信号,关闭A组件...");
        running = false;
    }

    /**
     * 检查此组件是否正在运行。
     * 1. 只有该方法返回false时,start方法才会被执行。
     * 2. 只有该方法返回true时,stop(Runnable callback)或stop()方法才会被执行。
     */
    @Override
    public boolean isRunning() {
        System.out.println("lifecycle 检查A组件的运行状态:" + running);
        return running;
    }
}

Spring每次调用start()stop()方法之前,都会调用下isRunning()方法。来检测下这个A组件,是否已经启动或停止过了。如果通过isRunning()方法,检测到A组件已经是运行状态了,就无需再调用start()方法启动A组件。

2. 把MyLifecycle交给Spring管理
<bean id="myLifecycle" class="com.kaka.spring.pojo.custom.MyLifecycle"/>

以上配置在lifecycle.xml文件中

3. 执行
    @Test
    public void lifecycleTest() {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
                "lifecycle.xml");
        // 必须显示调用
        classPathXmlApplicationContext.start();
        classPathXmlApplicationContext.stop();
    }

运行结果
在这里插入图片描述
这里强调一下,一定要显示调用容器的start()和stop()方法,Lifecycle的接口方法才会被执行。但是一般项目中(比如ssm和springboot),都不会显示调用容器的start()方法,所以就有了SmartLifecycle接口的出现。

三、再谈SmartLifecycle

SmartLifecycle是Lifecycle的一个子接口,比Lifecycle有更丰富的功能。其中有两点最重要的改进:

  1. 无需容器显示调用start()方法,就可以回调SmartLifecycle接口的start()
  2. 容器中如果有多个SmartLifecycle实例,可以方便控制调用顺序。

用法和Lifecycle一样,我们来看下

1. 定义一个类实现SmartLifecycle接口
public class MySmartLifecycle implements SmartLifecycle {
    private volatile boolean running = false;

    /**
     * 如果该`Lifecycle`类所在的上下文在调用`refresh`时,希望能够自己自动进行回调,则返回`true`* ,
     * false的值表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。
     */
    @Override
    public boolean isAutoStartup() {
        return true;
    }

    /**
     * 很多框架中的源码中,都会把真正逻辑写在stop()方法内。
     * 比如quartz和Redis的spring支持包
     *
     * @param callback
     */
    @Override
    public void stop(Runnable callback) {
        System.out.println("smartLifecycle stop runnable 容器停止...");
        stop();
        callback.run();
    }

    @Override
    public void start() {
        System.out.println("smartLifecycle 容器启动完成 ...");
        running = true;
    }

    @Override
    public void stop() {
        System.out.println("smartLifecycle stop 容器停止 ...");
        running = false;
    }

    @Override
    public boolean isRunning() {
        System.out.println("smartLifecycle 检查运行状态 ...");
        return running;
    }

    /**
     * 阶段值   越小越靠前执行start()方法,越靠后执行stop()方法
     *
     * @return
     */
    @Override
    public int getPhase() {
        return 0;
    }
}

一共需要实现6个方法,确实要不少啊,不是start()和stop()就行了吗?好吧,我们一个个解释下~

方法名描述
isAutoStartup()这个一定要返回true,不然就跟Lifecycle一样了。
getPhase()控制多个SmartLifecycle的回调顺序的,返回值越小越靠前执行start()方法,越靠后执行stop()方法
isRunning()与Lifecycle接口中的功能一样,用来判你的断组件是否在运行。
start()与Lifecycle接口中的功能一样,当刷新容器(也就是启动完成)时调用。
stop(Runnable callback)当容器停止时,回调该方法。当执行完你自定义的逻辑后,一定要调用下callback.run(); 这个是为了,告诉容器你已停止自己的组件完成。
这里多说一点,很多源码会在该方法内仅写两行代码,参考上面例子。一行是stop();把真正的逻辑转发到stop()这个方法。另一行就是必须调用的callback.run();
stop()不会被Spring框架调用到!
2. 把MySmartLifecycle交给Spring管理
<bean id="mySmartLifecycle" class="com.kaka.spring.pojo.custom.MySmartLifecycle"/>

以上配置在lifecycle.xml文件中

3. 执行
    @Test
    public void lifecycleTest() {
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(
                "lifecycle.xml");
        // 模拟框架中的停止方法
        classPathXmlApplicationContext.stop();
    }

执行结果在这里插入图片描述

四、总结

  • 需要根据Spring容器的生命周期,来做一些自己的逻辑时,一般都会选择自定义一个类,实现SmartLifecycle这个接口。很少有人会使用Lifecycle
  • 容器中有多个SmartLifecycle时,可以使用接口中的getPhase()方法控制回调的顺序。方法返回值越小,越靠前执行start()方法,越靠后执行stop()方法
  • SmartLifecycle这个接口的isAutoStartup()方法,一定要返回true,容器启动时才会回调SmartLifecycle的start()方法。
  • stop(Runnable callback)方法是有超时时间的,默认为30s。可以通过以下方式设置超时时间
<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐