美文网首页程序员
SpringBoot 两种消息机制触发启动和收尾

SpringBoot 两种消息机制触发启动和收尾

作者: 西5d | 来源:发表于2020-08-12 15:52 被阅读0次

    背景

    我们知道在开发中,springboot需要在自己本身的相关组件都启动和准备完毕后才可以正式处理请求。同样,在实例进行关闭时,实例中正在执行的任务,如果有必要最好是能主动的去做一些关闭操作,来避免出现未知的影响或者数据污染的情况。比如对自己定义的线程池做主动关闭,释放一些资源的连接,等待已在执行中的任务完成等。

    方案说明

    为了实现以上场景下的需求,这里就用到了SpringBoot或者说Spring的消息通知功能,重点是继承自ApplicationEvent(Spring-context)的SpringApplicationEvent(SpringBoot),而ApplicationEvent继承来自EventObject(jdk),这里SpringApplicationEvent的source是ApplicationContext

    ContextClosedEvent

    看名知义,该类型是在实例关闭的时候触发,在启动的时候会注册shutdownHook,当实例关闭的时候,shutdownHook触发org.springframework.context.support.AbstractApplicationContext.doClose()关闭动作,在这个方法里执行

    publishEvent(new ContextClosedEvent(this));
    

    ApplicationReadyEvent

    该事件是在启动过程中触发,在启动主要方法org.springframework.boot.SpringApplication.run(java.lang.String...)执行到最后,如下:

            try {
                listeners.running(context);
            }
            catch (Throwable ex) {
                handleRunFailure(context, ex, exceptionReporters, null);
                throw new IllegalStateException(ex);
            }
    
    

    运行各个SpringApplicationRunListener, 其中有一个是org.springframework.boot.context.event.EventPublishingRunListener,然后开启如下的调用,在这里会创建并发送ApplicationReadyEvent事件,表示Springboot上下文初始化完成。

    @Override
        public void running(ConfigurableApplicationContext context) {
            context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
            AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
        }
    
    

    代码实例

    public class MyRunnerBiz implements ApplicationListener<ApplicationReadyEvent> {
        
        //...
            @Override
            public void onApplicationEvent(ApplicationReadyEvent event) {
                new Thread(this::runWorker).start();
            }
        //...
        
    }
    
    

    注:这里单独新建个线程去执行任务,是为了方便本地debug不至于一直阻塞。

    @Slf4j
    @Component
    public class ShutdownListener implements ApplicationListener<ContextClosedEvent> {
    
        private static final int TIME_OUT = 5;
    
        @Autowired
        private List<Stopable> stopables;
    
        @Autowired
        private List<ExecutorService> executorServices;
    
        @Override
        public void onApplicationEvent(ContextClosedEvent event) {
            log.info("on context closed event ...");
            stopables.forEach(Stopable::stop);
            executorServices.forEach(executorService -> {
                if (!executorService.isShutdown()) {
                    log.info("shutdown executor :{} ...", executorService);
                    try {
                        executorService.shutdown();
                        executorService.awaitTermination(TIME_OUT, TimeUnit.MINUTES);
                    } catch (Exception e) {
                        log.error("wait time shutdown error.", e);
                    }
                }
            });
        }
    }
    

    说明

    主要介绍下第二部分关闭,都是通过spring依赖注入引入自定义的执行方法和线程池,因为这里线程池都是注册成bean的,可以放在一起统一管理。就不用每个地方去关闭;还有一个是部分功能bean实现了Stopable接口,用来完成扩展的关闭方式,可以理解成一个规范。
    以上就是这篇的全部内容,感谢阅读。

    相关文章

      网友评论

        本文标题:SpringBoot 两种消息机制触发启动和收尾

        本文链接:https://www.haomeiwen.com/subject/bxcmdktx.html