Graceful Shutdown Techniques for Spring Boot Applications
This article explains why graceful shutdown is important for Spring Boot services and demonstrates five practical methods—including Actuator shutdown, context closing, PID file handling, SpringApplication.exit, and a custom controller—each with complete code examples and usage instructions.
When stopping a Spring Boot service, using kill -9 terminates the process abruptly, preventing any cleanup logic from running; a graceful shutdown allows unfinished work to finish, logs to be flushed, and dependent services to be notified.
Method 1 – Actuator Shutdown Endpoint : Add the Actuator starter dependency, enable the shutdown endpoint, and expose it via management.endpoint.shutdown.enabled=true and management.endpoints.web.exposure.include=shutdown in application.properties . Create a bean with a @PreDestroy method to log when the bean is destroyed, and a configuration class that provides the bean. Trigger shutdown with curl -X POST http://localhost:3333/actuator/shutdown , which logs both startup and shutdown messages.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> server.port=3333
management.endpoint.shutdown.enabled=true
management.endpoints.web.exposure.include=shutdown package com.hqs.springboot.shutdowndemo.bean;
import javax.annotation.PreDestroy;
public class TerminateBean {
@PreDestroy
public void preDestroy() {
System.out.println("TerminalBean is destroyed");
}
} package com.hqs.springboot.shutdowndemo.config;
import com.hqs.springboot.shutdowndemo.bean.TerminateBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ShutDownConfig {
@Bean
public TerminateBean getTerminateBean() {
return new TerminateBean();
}
}Method 2 – Close Application Context Manually : Obtain the ConfigurableApplicationContext from SpringApplication.run , wait for a desired period (e.g., 10 seconds), then call ctx.close() . This also invokes any @PreDestroy methods.
ConfigurableApplicationContext ctx = SpringApplication.run(ShutdowndemoApplication.class, args);
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
ctx.close();Method 3 – PID File and External Kill : Configure Spring Boot to write its process ID to a file using ApplicationPidFileWriter . The PID can then be terminated with a shell command such as cat /path/to/app.pid | xargs kill , which still triggers @PreDestroy callbacks.
SpringApplication application = new SpringApplication(ShutdowndemoApplication.class);
application.addListeners(new ApplicationPidFileWriter("/Users/huangqingshi/app.pid"));
application.run();Method 4 – SpringApplication.exit : Call SpringApplication.exit(context, () -> 0) to obtain an exit code, then pass it to System.exit . This method ensures all shutdown hooks run and propagates the exit code to the JVM.
public static void exitApplication(ConfigurableApplicationContext context) {
int exitCode = SpringApplication.exit(context, (ExitCodeGenerator) () -> 0);
System.exit(exitCode);
}Method 5 – Custom Shutdown Controller : Implement a @RestController that holds the application context and provides an endpoint (e.g., /shutDownContext ) which calls ctx.close() . This allows remote shutdown via an HTTP POST request.
@RestController
public class ShutDownController implements ApplicationContextAware {
private ApplicationContext context;
@PostMapping("/shutDownContext")
public String shutDownContext() {
((ConfigurableApplicationContext) context).close();
return "context is shutdown";
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}All methods achieve graceful termination, but in production you must protect shutdown endpoints (e.g., firewall rules, internal‑network access) to avoid unauthorized use. The PID‑file approach (Method 3) is commonly employed, and when using in‑memory queues or thread pools, ensure pending tasks are completed or persisted before the service stops.
Java Captain
Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.