Programmatically shut down Spring Boot application
Solution 1
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
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
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
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
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 {
...
Axel Fontaine
Axel Fontaine is a serial entrepreneur, public speaker and software development expert based in Munich. He is the founder of CloudCaptain (previously known as Boxfuse). Their self-service cloud deployment platform enables hundreds of small and medium size companies to focus on development, while they take care of infrastructure and operations. CloudCaptain reliably and securely provisions our customers' applications in the AWS cloud and updates them with zero downtime thanks to their unique immutable infrastructure with minimal fully baked machine images approach. They also take care of all supporting resources including elastic IPs, load balancers, databases, security groups, DNS and more so that their customers can focus their attention where it matters most: delighting their users. In 2010 Axel also created Flyway, and grew it into the world's most popular database migration tool. By late 2017 he extended the project beyond its open-source roots and turned it into a very successful business, acquiring many of the world's largest companies and public institutions as customers for the new commercial pro and enterprise editions we launched. After just under two years of very rapid growth, he sold the company to Redgate in 2019. In the past he has also spoken regularly at many large international conferences including JavaOne, Devoxx, Jfokus, JavaZone, JAX and more about a wide range of topics including modular monoliths, immutable infrastructure and continuous delivery. As part of this he received the JavaOne RockStar speaker award and thanks to his broad industry contributions he was elected Java Champion by Oracle.
Updated on October 29, 2020Comments
-
Axel Fontaine over 3 years
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);
-
Anthony Chuinard almost 6 yearsUpvote for showing that the
ApplicationContext
can be automatically injected into other beans. -
StackOverFlow almost 6 years@snovelli how to invoke initiate shutdown method ? initiateShutdown(x) , x=0 ?
-
Abubacker Siddik over 5 yearsWhen there is conditional shutdown, this can be executed. SpringApplication.run(..).close() will do as the program completes.
-
Vlad G. over 5 yearsOk. Where am I supposed to get ExecutorServiceExitCodeGenerator? If it is a bean, can you show the creation snippet code (and from which class it is created)? In which class the method shutDown(ExecutorServiceExitCodeGenerator exitCodeGenerator) should be put?
-
Denys over 4 yearsIf I use ctx.close(); there is no need to call System.exit(n) at the end right? context close() should have System.exit() inside?
-
Sotirios Delimanolis over 4 years@Denys No, the context does not exit the java process on close. The exit in my example just demonstrates how the
ExitCodeGenerator
can be used. You could just return from themain
method to exit gracefully (exit code 0). -
Michaël COLL over 4 yearsJust a reminder this solution works for short lived process like batch, but don't use this on Spring MVC applications. The application just shutdown after booting.
-
ACV over 4 years@MichaelCOLL the question is about how to programatically shutdown a spring boot app regardless of type. It also works for Spring MVC
-
Michaël COLL over 4 years@ACV You're right it works, it works very well. But for an app that must stay up (like Spring MVC app), I think, it's not the good way of doing this. In my case, I've used
SpringApplication.exit(appContext, () -> returnCode)
. -
Rams over 4 yearswhy SpringApplication.(appContext, () -> returnCode); why can't appContext.close(). what is the difference ?
-
Savior about 4 yearsWhat VM are you referring to in your last line? If you're starting your Spring Boot application with
SpringApplication.run(MyApplication.class, args)
, then there is no parent context. There's only one context, the context created and returned byrun
, which you then immediatelyclose
. @Michael is right. This won't work for programs that need to do anything after the Spring context is initialized, which is most programs. -
ACV about 4 years@Savior JVM. There is a parent context. Here we're talking about how to shut down a Spring boot application. You normally don't shut down web applications this way. So this mechanism is usually used for short lived applications that do something then need to stop. By default, Spring boot will just keep on running even after you finished your batch processing so that's where you would want to use this mechanism.
-
Savior about 4 yearsWhich parent context do you think there is, from where?
run
creates a singleApplicationContext
, there's no hierarchy. Whether it's a web application or not, closing that context will destroy its beans (and shutdown thread pools) and, assuming the program doesn't do anything else unrelated to the context, will quit. I think the point@MichaelCOLL was trying to make is that you're better off capturing the context returned by
run` and callingclose
when you're ready to exit the application, based on some secondary signal. -
Savior about 4 yearsAlso, even if there was a parent context, you'd be shutting it down and destroying all of its beans, which wouldn't be much use to the other context, effectively breaking the application.
-
snovelli almost 4 years@StackOverFlow You need to inject the bean where you need it and then pass the return code as you suggested (x=0) if it's shutting down correctly. For example you could inject the Shutdown Manager into a RestController and allow remote shutdown, or you could inject it into a healthcheck monitoring that would shut the JVM down in case of missing downstream services
-
Forcuti Alessandro over 3 years@StackOverFlow ShutdownManager is a Component so it can be autowired too. I have placed it into a RestController because I must shutdown from a REST call for a domotica project
-
Jonas D over 3 years+! as required the
System.exit(exitCode)
in my application, otherwise spring boot was restarting -
Carlos López Marí over 2 yearsWhy would you save mannually the application context instead of autowiring it where needed?