DEV Community

Dev Cookies
Dev Cookies

Posted on

πŸ”„ Understanding the Spring Boot Lifecycle

Spring Boot applications go through a well-defined lifecycle, which can be divided into bean-level, application-level, and shutdown phases. Knowing this lifecycle is essential for initialization tasks, resource management, and graceful shutdown in production-grade microservices.


1️⃣ Application Startup Phases

When a Spring Boot application starts:

  1. SpringApplication bootstrap
  • Loads ApplicationContext.
  • Registers beans, configurations, and property sources.
  1. Bean instantiation & dependency injection
  • Spring creates all singleton beans.
  • Dependencies are injected (constructor, field, or setter injection).

a. Bean-Level Hooks

Hook When it Runs Use Case
@PostConstruct After bean is created & dependencies injected Lightweight initialization
InitializingBean.afterPropertiesSet() After properties are set Programmatic alternative to @PostConstruct
@Bean(initMethod="...") After bean creation (Java config) Legacy or custom init method

Example:

@Component
public class MyBean {
    @PostConstruct
    public void init() {
        System.out.println("Bean initialized");
    }
}
Enter fullscreen mode Exit fullscreen mode

b. Application-Level Hooks

Hook When it Runs Notes
CommandLineRunner After Spring context is ready Receives raw String[] args
ApplicationRunner After Spring context is ready Receives parsed ApplicationArguments
ApplicationReadyEvent After the app is fully started and server ready Ideal for warm-up tasks or metrics

Example with ApplicationReadyEvent:

@Component
public class AppReadyListener {
    @EventListener(ApplicationReadyEvent.class)
    public void onReady() {
        System.out.println("Application is fully started and ready to serve requests");
    }
}
Enter fullscreen mode Exit fullscreen mode

c. SmartLifecycle Interface

  • Used for complex beans that require start/stop order.
  • Provides start(), stop(), isRunning(), getPhase() methods.
@Component
public class MyLifecycleBean implements SmartLifecycle {
    @Override
    public void start() { System.out.println("Starting bean"); }
    @Override
    public void stop() { System.out.println("Stopping bean"); }
    @Override
    public boolean isRunning() { return true; }
    @Override
    public int getPhase() { return 0; } 
    @Override
    public boolean isAutoStartup() { return true; }
}
Enter fullscreen mode Exit fullscreen mode

2️⃣ Application Running

Once started:

  • Embedded web server (Tomcat/Jetty/Netty) is up.
  • Beans are ready to serve requests.
  • Tasks like cache warm-up or external service validation can safely run.

3️⃣ Application Shutdown

Spring Boot supports graceful shutdown, giving a chance to clean up resources:

a. Bean-Level Shutdown Hooks

Hook When it Runs Example
@PreDestroy Before bean destruction Close DB connections, release resources
DisposableBean.destroy() Programmatic cleanup alternative Same as @PreDestroy
@Component
public class CleanupBean {
    @PreDestroy
    public void cleanup() {
        System.out.println("Cleaning up resources before shutdown");
    }
}
Enter fullscreen mode Exit fullscreen mode

b. Application Context Close Event

  • Listen to ContextClosedEvent for global cleanup:
@Component
public class ShutdownListener {
    @EventListener(ContextClosedEvent.class)
    public void onShutdown() {
        System.out.println("Application context is closing");
    }
}
Enter fullscreen mode Exit fullscreen mode

4️⃣ Summary Timeline

SpringApplication.run()
        β”‚
        β–Ό
ApplicationContext initialized
        β”‚
        β–Ό
Bean instantiation & dependency injection
        β”‚
@PostConstruct / InitializingBean / init-method
        β”‚
        β–Ό
CommandLineRunner / ApplicationRunner
        β”‚
        β–Ό
ApplicationReadyEvent
        β”‚
        β–Ό
Application running (serving requests)
        β”‚
Shutdown initiated
        β”‚
@PreDestroy / DisposableBean / ContextClosedEvent
        β”‚
        β–Ό
Application stops
Enter fullscreen mode Exit fullscreen mode

5️⃣ Best Practices

  1. Separate lightweight vs heavy tasks
  • Use @PostConstruct for bean-level setup.
  • Use ApplicationReadyEvent or runners for heavy, app-wide initialization.
  1. Make startup tasks idempotent
  • Especially important for Kubernetes pods that may restart.
  1. Graceful shutdown
  • Always release resources and deregister services in shutdown hooks.
  1. Integrate with observability
  • Log startup/shutdown events, expose metrics, and integrate with readiness/liveness probes if running in Kubernetes.

This lifecycle understanding is crucial for microservices architecture, especially when combining Spring Boot hooks with Kubernetes pod lifecycle hooks like postStart and preStop.


Top comments (0)