Spring Boot / JavaFX:添加仍然可以访问 JPA 的关闭挂钩 (ctrl-c)

Spring Boot / JavaFX : adding a shutdown hook (ctrl-c) that still has access to JPA

这个问题已经被问过几次了,但我还没有找到 post 能准确描述我的情况。我有一个 JavaFX/Spring 基于启动的应用程序,需要它在关闭前执行一些清理任务。我可以像这样拦截按下 X 按钮的事件:

primaryStage.setOnCloseRequest(event -> 
{
    shutdown(event);
});

    private void shutdown(WindowEvent event)
    {
        if (event != null)
        {
            event.consume();
        }

        try 
        {
            shutdownProcessHub();

            Platform.exit();
        } 
        catch (Exception ex) 
        {
            logEntryService.logError(LogEntrySource.SERVICE, LogEntryType.CORE, "Error stopping process hub : " 
            + ex.getMessage(), logger);
        }
    }

我有一个关机按钮,它调用相同的方法但参数为空。这两种关闭我的应用程序的方法都会导致调用 shutdownProcessHub() 方法,该方法可以优雅地停止一堆线程并执行对数据库的写入。

问题是此应用程序也可以 运行 没有 GUI。在此部署模式下,我使用 NSSM 创建一个指向启动应用程序的批处理文件的 windows 服务。停止上述服务会导致对应用程序进行 CTRL-C 调用,从而完全绕过我的关闭方法。我使用以下代码注册了一个关闭钩子:

Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdown(null)));

在任何形式的 Spring bean 被长期销毁后 运行s 清楚地说关闭挂钩,因为我在将 CTRL-C 发送到 CMD window 时收到以下异常运行安装 JAR :

Exception in thread "Thread-5" org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is java.lang.IllegalStateException: EntityManagerFactory is closed

我需要做什么才能让关闭挂钩仍然能够访问实体管理器?我知道这在 Spring / JVM 生命周期中可能为时已晚,仍然无法访问其中任何一个,正确拦截 CTRL-C 调用的替代方法是什么?

看起来 SmartLifeCycle 接口的 stop() 方法正是我所需要的。它在命令提示符 运行 JAR 中执行 CTRL-C 时被调用,并且仍然可以访问所有 Spring 的资源,包括 JPA 的实体管理器。唯一的问题是当此方法执行时 Log4J2 似乎不可用,但这只是一个小麻烦。

干杯