Programmatically shut down Spring Boot application

JavaSpringSpring Boot

Java Problem Overview


How can I programmatically shutdown a Spring Boot application without terminating the VM?

In other works, what is the opposite of

new SpringApplication(Main.class).run(args);

Java Solutions


Solution 1 - Java

Closing a SpringApplication basically means closing the underlying ApplicationContext. The SpringApplication#run(String...) method gives you that ApplicationContext as a ConfigurableApplicationContext. You can then close() it yourself.

For example,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to shut down...
        ctx.close();
    }
}

Alternatively, you can use the static SpringApplication.exit(ApplicationContext, ExitCodeGenerator...) helper method to do it for you. For example,

@SpringBootApplication
public class Example {
    public static void main(String[] args) {
        ConfigurableApplicationContext ctx = SpringApplication.run(Example.class, args);
        // ...determine it's time to stop...
        int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
            @Override
            public int getExitCode() {
                // no errors
                return 0;
            }
        });

        // or shortened to
        // int exitCode = SpringApplication.exit(ctx, () -> 0);

        System.exit(exitCode);
    }
}

Solution 2 - Java

The simplest way would be to inject the following object where you need to initiate the shutdown

ShutdownManager.java

import org.springframework.context.ApplicationContext;
import org.springframework.boot.SpringApplication;

@Component
class ShutdownManager {

    @Autowired
    private ApplicationContext appContext;

    /*
     * Invoke with `0` to indicate no error or different code to indicate
     * abnormal exit. es: shutdownManager.initiateShutdown(0);
     **/
    public void initiateShutdown(int returnCode){
        SpringApplication.exit(appContext, () -> returnCode);
    }
}

Solution 3 - Java

This works, even done is printed.

  SpringApplication.run(MyApplication.class, args).close();
  System.out.println("done");

So adding .close() after run()

Explanation:

> public ConfigurableApplicationContext run(String... args) > > Run the Spring application, creating and refreshing a new > ApplicationContext. Parameters: > > args - the application arguments (usually passed from a Java main > method) > > Returns: > a running ApplicationContext

and:

> void close() Close this application context, releasing all resources > and locks that the implementation might hold. This includes destroying > all cached singleton beans. Note: Does not invoke close on a parent > context; parent contexts have their own, independent lifecycle. > > This method can be called multiple times without side effects: > Subsequent close calls on an already closed context will be ignored.

So basically, it will not close the parent context, that's why the VM doesn't quit.

Solution 4 - Java

This will make sure that the SpringBoot application is closed properly and the resources are released back to the operating system,

@Autowired
private ApplicationContext context;

@GetMapping("/shutdown-app")
public void shutdownApp() {

    int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
    System.exit(exitCode);
}

Solution 5 - Java

In the application you can use SpringApplication. This has a static exit() method that takes two arguments: the ApplicationContext and an ExitCodeGenerator:

i.e. you can declare this method:

@Autowired
public void shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) {
    SpringApplication.exit(applicationContext, exitCodeGenerator);
}

Inside the Integration tests you can achieved it by adding @DirtiesContext annotation at class level:

  • @DirtiesContext(classMode=ClassMode.AFTER_CLASS) - The associated ApplicationContext will be marked as dirty after the test class.
  • @DirtiesContext(classMode=ClassMode.AFTER_EACH_TEST_METHOD) - The associated ApplicationContext will be marked as dirty after each test method in the class.

i.e.

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {Application.class},
    webEnvironment= SpringBootTest.WebEnvironment.DEFINED_PORT, properties = {"server.port:0"})
@DirtiesContext(classMode= DirtiesContext.ClassMode.AFTER_CLASS)
public class ApplicationIT {
...

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAxel FontaineView Question on Stackoverflow
Solution 1 - JavaSotirios DelimanolisView Answer on Stackoverflow
Solution 2 - JavasnovelliView Answer on Stackoverflow
Solution 3 - JavaACVView Answer on Stackoverflow
Solution 4 - JavasamView Answer on Stackoverflow
Solution 5 - JavamagiccrafterView Answer on Stackoverflow