Shutdown a Spring Boot Application

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. 

2 thoughts on “Shutdown a Spring Boot Application”

  1. ConfigurableApplicationContext’s close() method seems to be package private, so the code above that calls it won’t work. Right?

Comments are closed.