Spring 出现异常时不调用启动 onApplicationEvent(ContextClosedEvent 事件)

Spring Boot onApplicationEvent(ContextClosedEvent event) not called on in case of exception

下面是示例代码,即

@Override
    public void run(ApplicationArguments applicationArguments) throws Exception {
        log.info("Starting...");
        mainThread.start();
        mainThread.join();
        log.info("Exiting...");
    }

    @EventListener
    public void onApplicationEvent(ContextClosedEvent event) {
        log.info("Inside on ApplicationEvent");
        mainThread.interrupt();
        log.info("Thread Interupted");
    }

    @Override
    public void run() {
        try {
            someAppLogic.doLogic();
        } catch (Exception e) {
            if (e instanceof  InterruptedException || e.getCause() instanceof InterruptedException) {
                log.info("Interrupted...");
            } else {
                log.error("Exception occurred", e);
                exitCode = 1;
            }
        }
    }
  1. someAppLogic.doLogic();在 Spring 引导应用程序启动
  2. 时在 mainThread 中被调用
  3. 目标是在发生异常的情况下在 ApplicationEvent 的方法中让 mainThread 中断 在 someAppLogic.doLogic();退出代码为 1.

但问题是 onApplicationEvent 中的 main.interrupt() 永远不会 调用 以防出现异常 来自 运行 方法,即当 someAppLogic.doLogic() 抛出异常时。

这个 Spring 引导应用程序将部署在 Kubernetes 中,因此包含它的 pod 应该正常关闭。

所以问题是 如何处理 someAppLogic.doLogic(); 抛出的异常优雅地发送 exitcode 作为 1 ?

您需要在 ConfigurableApplicationContext 上调用 close() 才能发布 ContextClosedEvent。

    //you need to figure out how to get hold of this object
    private ConfigurableApplicationContext context;
    
    @Override
    public void run() {
        try {
            someAppLogic.doLogic();
        } catch (Exception e) {
            if (e instanceof  InterruptedException || e.getCause() instanceof InterruptedException) {
                log.info("Interrupted...");
            } else {
                log.error("Exception occurred", e);
                exitCode = 1;
                //call close
                context.close();
            }
        }
    }