javaspring-bootjavafxentitymanagershutdown-hook

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


This question has been asked a few times but I have not found a post that describes my situation exactly. I have a JavaFX/Spring boot based application that is required to perform some cleanup tasks before shutting down. I can intercept the event for the X button being pressed like so :

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);
        }
    }

I have a shutdown button which calls the same method but with a null argument. Both these methods of shutting down my application result in the shutdownProcessHub() method being called which gracefully stops a bunch of threads and performs writes to the database.

The issue is that this application can also be run with no GUI. In this deployment mode, i use NSSM to create a windows service that points to a batch file which starts the app. Stopping said service results in a CTRL-C call to the app which completely bypasses my shutdown method. I have used the following code to register a shutdown hook :

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

Said shutdown hook clearly runs after any form of Spring bean has been long destroyed since i'm getting the following exception when sending CTRL-C to the CMD window running the 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

What do i need to do in order to have the shutdown hook still be able to access the entity manager? I understand this might be too late in the Spring / JVM lifespan for any of these to still be accessible, what would be the alternative for a CTRL-C call to be correctly intercepted?


Solution

  • looks like the SmartLifeCycle interface's stop() method is what i needed. It is called when doing CTRL-C in the command prompt running the JAR and still has access to all of Spring's resources including JPA's entity manager. The only issue is that Log4J2 seems to not be available while this method executes but that is only a minor annoyance.

    Cheers