Shutdown a Spring Boot Application

Spread the love

1. Overview

Managing the lifecycle of Spring Boot Application is very important for a production-ready system. The Spring container handles the creation, initialization, and destruction of all the Beans with the help of the ApplicationContext.

The emphasize of this write-up is the destruction phase of the lifecycle. More specifically, we’ll have a look at different ways to shut down a Spring Boot Application.

2. 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.0.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.dailycodebuffer.example</groupId>
	<artifactId>Spring-Boot-Shutdown</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>Spring-Boot-Shutdown</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>11</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-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</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=*

2.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>

To shut down the Spring Boot application, we simply call a POST method like this:

curl -X POST localhost:port/actuator/shutdown

In this call, the port represents the actuator port.

3. Close ApplicationContext

Another option to shutdown the 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();
 }
}

To handle the ApplicationContext close event, let’s create a 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");
 }
}

4. Exit SpringApplication

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);
 }
}

5. Kill Application Process

Use the 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(SpringBootShutdownApplication.class);
application.addListeners(new ApplicationPidFileWriter("./bin/app.pid"));
application.run();

Next, create a shutdown.bat file with the following content:

kill $(cat ./bin/app.pid)

The execution of shutdown.bat extracts the Process ID from the app.pid file and uses the kill command to terminate the Boot application.

6. Conclusion

In this quick write-up, we’ve covered a few simple methods that can be used to shut down a running Spring Boot Application.

While it’s up to the developer to choose an appropriate method; all of these methods should be used by design and on purpose.

For example, .exit() is preferred when we need to pass an error code to another environment, say JVM for further actions. Using Application PID gives more flexibility, as we can also start or restart the application with the use of a bash script.

Finally, /shutdown is here to make it possible to terminate the applications externally via HTTP. For all the other cases .close() will work perfectly.