如何理解并使用SpringApplicationRunListener实现生命周期监听?

67 阅读2分钟

生命周期监听

1、监听器-SpringApplicationRunListener

  1. 自定义SpringApplicationRunListener

    1.1. 实现SpringApplicationRunListener接口
    1.2. 配置实现接口的类,配置的位置是spring-boot-3.0.2.jar包下的META-INF/spring.factories
    1.3. 在配置的时候,可以参考SpringBoot内部配置示例

# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
package com.beite.boot.core.listener.run;

import com.beite.boot.core.demos.web.BasicController;
import org.springframework.boot.ConfigurableBootstrapContext;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;

import java.time.Duration;

/**
 * @author beite_he[beite_he@insightfo.cn]
 * @author <a href="mailto:beite_he@insightfo.cn">Beite</a>
 * @date 2024年10月22日 00:01
 * @since 1.0
 */
public class MyAppListener implements SpringApplicationRunListener {

    /**
     *    SpringApplicationRunListener得调用,都需要从src/main/resources/META-INF/spring.factories中获取,
     *    对应的源码为:
     *  类:SpringApplication
     *  方法:private <T> List<T> getSpringFactoriesInstances(Class<T> type, ArgumentResolver argumentResolver) {
     *     return SpringFactoriesLoader.forDefaultResourceLocation(getClassLoader()).load(type, argumentResolver);
     *      }
     */

    /**
     *  应用开始启动,当  SpringApplication.run(Boot306CoreApplication.class, args)运行
     *  只要引导对象创建完成BootstrapContext后就执行该starting方法
     * @param bootstrapContext the bootstrap context
     */
    @Override
    public void starting(ConfigurableBootstrapContext bootstrapContext) {
        System.out.println("========hello starting========");
    }

    /**
     * 环境准备完成(把启动参数等绑定到环境变量中),但是IOC容器还没准备好
     * @param bootstrapContext the bootstrap context
     * @param environment the environment
     */
    @Override
    public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
        // 可以在此处获取系统的相关配置,列如我在yml中配置的服务端口
        String property = environment.getProperty("server.port");
        System.out.println("========hello environmentPrepared========,端口号:" + property);
    }

    /**
     *  ioc容器创建并准备好,但是sources(主配置类)没加载。并关闭引导上下文;组件都没创建
     * @param context the application context
     */
    @Override
    public void contextPrepared(ConfigurableApplicationContext context) {
        System.out.println("========hello contextPrepared========");
    }

    /**
     * ioc容器加载。主配置类加载进去了。但是ioc容器还没刷新(我们的bean没创建)。
     * @param context the application context
     */
    @Override
    public void contextLoaded(ConfigurableApplicationContext context) {
        System.out.println("========hello contextLoaded========");
    }

    /**
     * IOC容器刷新完成(所有BEAN已创建),但是runner没有调用
     * @param context the application context.
     * @param timeTaken the time taken to start the application or {@code null} if unknown
     */
    @Override
    public void started(ConfigurableApplicationContext context, Duration timeTaken) {
        BasicController bean = context.getBean(BasicController.class);
        System.out.println(bean);
        System.out.println("========hello started========");
    }

    /**
     *IOC容器刷新完成(所有BEAN已创建),但是runner已经调用
     * 进入就绪状态
     * @param context the application context.
     * @param timeTaken the time taken for the application to be ready or {@code null} if
     * unknown
     */
    @Override
    public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
        System.out.println("========hello ready========");
    }

    /**
     *  Spring应用创建失败
     * @param context the application context or {@code null} if a failure occurred before
     * the context was created
     * @param exception the failure
     */
    @Override
    public void failed(ConfigurableApplicationContext context, Throwable exception) {
        System.out.println("========hello failed========");
    }
}

2、生命周期示意图

yuque_diagram.jpg

3、使用建议

如果需要干涉生命周期某个时机做事情,可以使用该接口实现