所有分类
  • 所有分类
  • 未分类

Spring容器生命周期–SmartLifecycle的用法

简介

说明

本文介绍Spring容器生命周期SmartLifeCycle的用法。

Bean的初始化方法和销毁方法是Bean生命周期级别的;而Lifecycle是容器生命周期级别的。如果我们想在容器本身的生命周期(比如容器启动完成后、停止之前)事件上做一些工作,可以使用LifeCycle接口。

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

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

方法

方法名描述
isAutoStartup()一定要返回true。否则,容器启动时不会回调start()方法。 true:让Lifecycle类所在的上下文在调用`refresh`时,能够自己自动进行回调。
false:表明组件打算通过显式的start()调用来启动,类似于普通的Lifecycle实现。这个一定要返回true,不然就跟Lifecycle一样了。
getPhase()控制多个SmartLifecycle的回调顺序的:越小:start()方法越靠前,stop()方法越靠后
isRunning()与Lifecycle接口中的功能一样,用来判你的断组件是否在运行。
start()如果类A没在运行(isRunning返回false),则走该方法;否则不走该方法。 当刷新容器(启动完成)时调用。跟Lifecycle接口一样。
stop(Runnable callback)当容器停止时,回调该方法。 当执行完你自定义的逻辑后,一定要调用下callback.run(); 这是为了,告诉容器你已停止自己的组件完成。
很多源码会在该方法内仅写两行代码,参考下面例子。一行是stop():把真正的逻辑转发到stop()这个方法。另一行就是必须调用的callback.run(); 此方法是有超时时间的,默认为30s。可以通过以下方式设置超时时间
stop()需要自己调用。不会被Spring框架调用到

stop(Runnable callback)

官网网址:Spring 5.0.0框架介绍_中文版_3.6

在SmartLifecycle中定义的停止方法接收一个回调函数,关闭进程完成之后都会调用回调的run()方法。可以进行异步关闭,因为LifecycleProcessor接口、DefaultLifecycleProcessor接口的默认实现会等待每个阶段的对象组直到达到超时值,然后调用回调函数。默认每个阶段的超时值为30秒。可以在上下文中通过定义名为”lifecycleProcessor”的bean来覆盖默认的生命周期处理器实例。如果你只想修改超时值,这样改即可:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.support.DefaultLifecycleProcessor;

@Configuration
public class AppConfig {
    @Bean
    public DefaultLifecycleProcessor lifecycleProcessor() {
        DefaultLifecycleProcessor processor = new DefaultLifecycleProcessor();
        processor.setTimeoutPerShutdownPhase(30000);
        return processor;
    }
}

简单示例

代码

package com.example.config;

import org.springframework.context.SmartLifecycle;
import org.springframework.stereotype.Component;

@Component
public class MySmartLifecycle implements SmartLifecycle {
    private volatile boolean running = false;

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

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

    @Override
    public void start() {
        System.out.println("start()");
        running = true;
    }

    @Override
    public void stop() {
        System.out.println("stop()");
        running = false;
    }

    @Override
    public boolean isRunning() {
        System.out.println("isRunning()");
        return running;
    }

    /**
     * 阶段值。越小:start()方法越靠前,stop()方法越靠后
     */
    @Override
    public int getPhase() {
        System.out.println("getPhase()");
        return 0;
    }
}

测试

启动时:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.3.0.RELEASE)

2021-03-09 19:30:57.138  INFO 6600 --- [           main] com.example.DemoApplication              : Starting DemoApplication on DESKTOP-QI6B9ME with PID 6600 (E:\work\Idea_proj\demo_JAVA\demo_SpringBoot\target\classes started by Liu in E:\work\Idea_proj\demo_JAVA\demo_SpringBoot)
2021-03-09 19:30:57.143  INFO 6600 --- [           main] com.example.DemoApplication              : No active profile set, falling back to default profiles: default
2021-03-09 19:30:57.899  INFO 6600 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2021-03-09 19:30:57.907  INFO 6600 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2021-03-09 19:30:57.907  INFO 6600 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.35]
2021-03-09 19:30:57.986  INFO 6600 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2021-03-09 19:30:57.986  INFO 6600 --- [           main] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 808 ms
2021-03-09 19:30:58.135  INFO 6600 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
getPhase()
isRunning()
start()
2021-03-09 19:30:58.260  INFO 6600 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2021-03-09 19:30:58.268  INFO 6600 --- [           main] com.example.DemoApplication              : Started DemoApplication in 1.442 seconds (JVM running for 2.44)

关闭时:

getPhase()
isRunning()
stop(callback)
stop()

与ApplicationRunner的执行顺序

SmartLifecycle 的 start() 方法会在 ApplicationRunner 的 run() 方法之前执行。具体的顺序如下:

  1. Spring Boot 应用程序启动
  2. 所有实现了 SmartLifecycle 接口的 Bean 的 start() 方法会被依次调用,按照 getPhase() 方法返回值的顺序进行排序。
  3. 所有实现了 ApplicationRunner 接口的 Bean 的 run() 方法会被调用,按照 Spring 容器中 Bean 的加载顺序执行。

总结:SmartLifecycle 的 start() 方法会在应用程序启动过程中首先执行,然后才会执行 ApplicationRunner 的 run() 方法。这样可以确保在应用程序启动完成后,已经完成了所有需要在启动阶段执行的逻辑。

0

评论0

请先

显示验证码
没有账号?注册  忘记密码?

社交账号快速登录