Graceful Shutdown in Spring Boot 2.3.4: Configuration, Code Examples, and Shutdown Mechanisms

This article explains how Spring Boot 2.3.4 implements graceful shutdown for Jetty, Reactor Netty, Tomcat and Undertow, shows the simple YAML configuration, demonstrates code examples using DisposableBean and @PreDestroy, and describes the actuator shutdown endpoint and its relevance to Kubernetes liveness and readiness probes.

Architect's Tech Stack
Architect's Tech Stack
Architect's Tech Stack
Graceful Shutdown in Spring Boot 2.3.4: Configuration, Code Examples, and Shutdown Mechanisms

Graceful Shutdown

Spring Boot 2.3.4 introduces improved graceful shutdown support for Jetty, Reactor Netty, Tomcat, and Undertow, applicable to both reactive and servlet‑based web applications.

The purpose of graceful shutdown is to avoid abrupt termination (kill -9) that can cause in‑flight requests to fail and produce dirty data.

When graceful shutdown is enabled, the server reserves a short period after receiving a SIGINT (kill -2) during which no new requests are accepted and existing requests are allowed to complete. Different servers handle new requests differently: Reactor Netty and Tomcat stop accepting, Undertow returns 503.

New Configuration

YAML Configuration

The new configuration is simple: set server.shutdown=graceful. This requires Tomcat 9.0.33 or newer.

server:
  port: 6080
  shutdown: graceful # enable graceful shutdown
spring:
  lifecycle:
    timeout-per-shutdown-phase: 20s # buffer time, default 30s

After configuring timeout-per-shutdown-phase, if a thread cannot finish within the buffer time it will be forced to stop.

Logs with and without graceful shutdown differ; with graceful shutdown you will see “Waiting for active requests to complete” before the container stops.

Shutdown Methods

Do not use kill -9; use kill -2 to trigger the JVM shutdown hook. Alternatively, invoke the /actuator/shutdown endpoint via a POST request.

Adding a ShutdownHook

Implement DisposableBean and override destroy(), or annotate a method with @PreDestroy. The @PreDestroy method runs before the DisposableBean method.

@Slf4j
@Service
public class DefaultDataStore implements DisposableBean {
    private final ExecutorService executorService = new ThreadPoolExecutor(
        OSUtil.getAvailableProcessors(),
        OSUtil.getAvailableProcessors() + 1,
        1,
        TimeUnit.MINUTES,
        new ArrayBlockingQueue<>(200),
        new DefaultThreadFactory("UploadVideo"));
    @Override
    public void destroy() throws Exception {
        log.info("Preparing graceful shutdown using DisposableBean");
        executorService.shutdown();
    }
}
@Slf4j
@Service
public class DefaultDataStore {
    private final ExecutorService executorService = new ThreadPoolExecutor(
        OSUtil.getAvailableProcessors(),
        OSUtil.getAvailableProcessors() + 1,
        1,
        TimeUnit.MINUTES,
        new ArrayBlockingQueue<>(200),
        new DefaultThreadFactory("UploadVideo"));
    @PreDestroy
    public void shutdown() {
        log.info("Preparing graceful shutdown @PreDestroy");
        executorService.shutdown();
    }
}

The shutdown process ultimately calls this.context.close(), which invokes AbstractApplicationContext.doClose() to destroy beans and remove the JVM shutdown hook.

Shutdown Endpoint

Spring Boot’s actuator provides a ShutdownEndpoint (disabled by default). When enabled, a POST to /actuator/shutdown triggers the same graceful shutdown logic.

@Configuration(proxyBeanMethods = false)
@ConditionalOnAvailableEndpoint(endpoint = ShutdownEndpoint.class)
public class ShutdownEndpointAutoConfiguration {
    @Bean(destroyMethod = "")
    @ConditionalOnMissingBean
    public ShutdownEndpoint shutdownEndpoint() {
        return new ShutdownEndpoint();
    }
}

The endpoint’s shutdown() method checks the application context, performs the shutdown, and returns a status map.

Afterword

Graceful shutdown in a single‑node Spring Boot application only guarantees that the server’s internal threads finish; client‑side state is not handled. In distributed systems (Dubbo, cloud services), you must deregister the service from the registry before stopping it to avoid 503 errors.

Kubernetes integration in Spring Boot 2.3 adds Liveness and Readiness probes, which help manage container lifecycle and traffic routing during shutdown.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MicroservicesKubernetesSpring BootGraceful Shutdown
Architect's Tech Stack
Written by

Architect's Tech Stack

Java backend, microservices, distributed systems, containerized programming, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.