In this post, we will discuss different options to shutdown a Spring Boot application. Please read the Spring Boot Starters and Spring Boot Configuration for the initial setup of Spring Boot application.
Introduction
Managing your application in the production environment is different than the development environment. We may want to control the life cycle of our production deployed application. Spring Boot provides some ready to use features to handle the lifecycle of Spring container including shutdown a Spring Boot application gracefully. Let’s discuss some of the most common ways to control Spring Boot enterprise applications on the production environment.
1. Shutdown Using Actuator EndPoint
Spring Boot Actuator comes with many production-ready features which include /shutdown
endpoint. By default, all /shutdown
endpoint is not enabled in the Actuator. To use this endpoint in our application, we should include spring-boot-starter-actuator
starter and enable this endpoint in our application.
To include and enable this, we need to add spring-boot-starter-actuator starter in our application pom.xml
and require to enable /shutdown
endpoint using application.properties
or application.yml
file. Here is our maven dependency to set up this.
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.javadevjournal</groupId>
<artifactId>spring-boot-shutdown</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>spring-boot-shutdown</name>
<description>How to Shutdown a Spring Boot Application gracefully</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.4.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
To configure the enablement of an endpoint, use its management.endpoint..enabled
property. This is how our application.properties
look like after adding the changes
management.endpoint.shutdown.enabled=true
management.endpoint.info.enabled=true
management.endpoints.web.exposure.include=*
1.1 Secure Endpoint
In this example, we are exposing /endpoint
without any security. Performing this on your production application is not recommended. This can cause a big security risk for your application. To protect your shutdown endpoint, use a spring-boot-starter-security
starter.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
1.2 Test Endpoint
To test the /shutdown
endpoint, run the Spring Boot application, once the application is up and running, simply call a POST method to the /shutdown
endpoint
curl -i -X POST http://localhost:8080/actuator/shutdown
A response similar to the following is produced:
HTTP/1.1 200
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 05 Aug 2018 18:11:27 GMT
{
"message":"Shutting down, bye..."
}
Check the server console/log, you have the similar output
2018-08-05 11:11:28.151 INFO 9626 --- [ Thread-28] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@42f0c846: startup date [Sun Aug 05 11:10:58 PDT 2018]; root of context hierarchy
2018-08-05 11:11:28.155 INFO 9626 --- [ Thread-28] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2. Close ApplicationContext
Another option to shutdown Spring Boot application is to close Spring ApplicationContext
using SpringApplication
. SpringApplication#run(String…) method returns ApplicationContext
as a <ConfigurableApplicationContext.
We can use close()
method to close ApplicationContext programmatically.
@SpringBootApplication
public class SpringBootShutdownApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootShutdownApplication.class, args);
ctx.close();
}
}
When you run the application, we have the similar output on the server console or log files.
2018-08-05 11:32:19.898 INFO 9899 --- [ restartedMain] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@72d1ddb3: startup date [Sun Aug 05 11:32:16 PDT 2018]; root of context hierarchy
2018-08-05 11:32:19.901 INFO 9899 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
To handle ApplicationContext close event, let’s create shut down handle method using @PreDestroy
annotation.
@Configuration
public class ApplicationConfig {
@PreDestroy
public void onShutDown() {
System.out.println("closing application context..let's do the final resource cleanup");
}
}
On running out the application, we see similar output
2018-08-05 22:24:48.487 INFO 10550 --- [ restartedMain] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@451a9713: startup date [Sun Aug 05 22:24:45 EDT 2018]; root of context hierarchy
2018-08-05 22:24:48.490 INFO 10550 --- [ restartedMain] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
closing application context..let's do the final resource cleanup
3. Exist Using SpringApplication#exit
We also have the option to use the static exit helper method available with SpringApplication
class.
@SpringBootApplication
public class SpringBootShutdownApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx = SpringApplication.run(SpringBootShutdownApplication.class, args);
exitApplication(ctx);
//ctx.close();
}
public static void exitApplication(ConfigurableApplicationContext ctx) {
int exitCode = SpringApplication.exit(ctx, new ExitCodeGenerator() {
@Override
public int getExitCode() {
// no errors
return 0;
}
});
System.exit(exitCode);
}
}
With Java 8 Lambda, above code can be rewritten as
SpringApplication.exit(ctx, () -> returnCode);
4. Kill Application Process
Use Spring Boot application to write the PID into a file. We can use the PID file to stop or restart or get the status using a bash script. We use ApplicationPidFileWriter
to write PID to file.
SpringApplication application = new SpringApplication(Application.class);
application.addListeners(new ApplicationPidFileWriter("./bin/app.pid"));
application.run();
Read the article to understand how to write the bash script.
Summary
In this post, we discuss different options to shutdown a Spring Boot application. We learned about the /shutdown endpoint available under Spring Boot Actuator for shutting down our application using HTTP. We did talk about closing ApplicationContext using the SpringAppication#close
method. In the last section, we learned how to write the PID into a file and how to use a bash script to control the application lifecycle.
There is no predefined rule about these options. This is for us to choose the best option based on our use case. The complete code for this article is available on GitHub.
ConfigurableApplicationContext’s close() method seems to be package private, so the code above that calls it won’t work. Right?
No, this is still available (https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ConfigurableApplicationContext.html#close–)
If you like you can also use the new AutoCloseable interface implementation.