How to prevent Spring app context shutdown until shutdown hook is fired

前端 未结 2 1538
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-22 12:45

I have a spring-boot application.

I have implemented SmartLifecycle interface in my bean which starts async snmp server in it\'s start method and stops it i

相关标签:
2条回答
  • 2021-01-22 13:30

    My investigation lead me to the core of the problem: daemon threads.

    The snmp server implementation which I use (snmp4j) use daemon threads internally. So even when snmp server started, there are no more live user threads in JVM, so it exits.

    TL/DR:

    Just add this method to any bean (snmp server bean is good candidate for this):

    @Scheduled(fixedDelay = 1000 * 60 * 60) // every hour
    public void doNothing() {
        // Forces Spring Scheduling managing thread to start
    }
    

    (Do not forget to add @EnableScheduling to your spring configuration).

    Explanation:

    To prevent stopping spring context, while SNMP server is still running, we need any non-daemon thread to be alive in JVM. Not necessarily main thread. So we can let main method to finish.

    1. We can run new non-daemon thread from our server bean's start method. This thread will wait on some lock in while loop checking for some running variable, while our stop method will set this running variable to false and notifyAll on this lock.

      This way, our non-daemon thread will be alive until shotdown hook is triggered (and prevents JVM to exit). After shutdown hook, spring context lifecycle close method will call all SmartLifecycle bean's close methods, that will lead to SNMP server bean's stop method call, that will lead to set running to false, that will lead to our non-daemon thread to stop, that allow JVM to stop gracefully.

    2. Or instead we can use Spring's scheduling thread in similar way. It also is non-daemon thread, so it will prevent JVM to exit. And Spring manages this thread itself, so it will automatically stop it when shutdown hook is triggered.

      To make Spring's scheduling thread to start we need any @Scheduled method in any bean.


    I think that first (manual) approach is still more "correct", while requires more async coding (which is error-prone as we all know). Who knows how Spring will change it's scheduling implementation in the future.

    0 讨论(0)
  • 2021-01-22 13:31
        SpringApplication app = new SpringApplication(Main.class);
        app.setRegisterShutdownHook(false);
        ConfigurableApplicationContext applicationContext= app.run();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override
            public void run() {
                //do your things
                applicationContext.close();
            }
        }));
    
    0 讨论(0)
提交回复
热议问题