Understanding Application Lifecycle

1. Understanding Spring Boot Startup Sequence

Boot Startup Phases

  1. Bootstrap context (if Spring Cloud)
  2. Create SpringApplication, deduce web type (servlet/reactive/none)
  3. Run ApplicationContextInitializers
  4. Prepare Environment (load profiles, properties)
  5. Print banner
  6. Create ApplicationContext
  7. Apply BeanFactoryPostProcessors & BeanPostProcessors
  8. Refresh context → instantiate singletons
  9. Call ApplicationRunner / CommandLineRunner
  10. Publish ApplicationReadyEvent

2. Using ApplicationRunner and CommandLineRunner

Interface Args Type Use Case
CommandLineRunner String[] Raw arguments
ApplicationRunner ApplicationArguments Parsed options (--name=value)

Example: Seed data on startup

@Component
public class Seeder implements ApplicationRunner {
  private final UserRepository repo;
  public Seeder(UserRepository repo) { this.repo = repo; }
  @Override public void run(ApplicationArguments args) {
    if (args.containsOption("seed")) repo.saveAll(defaults());
  }
}

3. Implementing ApplicationContextInitializer

Use Description
Pre-refresh tweaks Modify environment, register beans before refresh
Register spring.factories or application.addInitializers(...)

Example: Inject property source on context init

public class TenantInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
  @Override public void initialize(ConfigurableApplicationContext ctx) {
    ctx.getEnvironment().getPropertySources()
       .addFirst(new MapPropertySource("tenant", Map.of("tenant.id", System.getenv("TENANT"))));
  }
}

4. Using SmartLifecycle for Custom Lifecycle Management

Method Purpose
start() Called when context starts
stop(Runnable) Async shutdown callback
isRunning() State query
getPhase() Lower phase = earlier start, later stop
isAutoStartup() Auto-start with context

5. Handling Application Ready Events (ApplicationReadyEvent)

Example: Warm caches on ApplicationReadyEvent

@Component
public class ReadyHandler {
  @EventListener(ApplicationReadyEvent.class)
  public void onReady() { /* warm caches, register with discovery */ }
}
Note: Fired after context refresh AND runners — safe place to do work that requires app fully started.

6. Handling Application Started Events

Event Fired When
ApplicationStartingEvent Run starts, before context
ApplicationEnvironmentPreparedEvent Environment ready
ApplicationContextInitializedEvent After initializers
ApplicationPreparedEvent Context loaded but not refreshed
ApplicationStartedEvent Context refreshed, before runners
ApplicationReadyEvent After runners
ApplicationFailedEvent Startup failure

7. Handling Context Refresh Events

Example: Handle ContextRefreshedEvent

@EventListener(ContextRefreshedEvent.class)
public void onRefresh(ContextRefreshedEvent e) {
  ApplicationContext ctx = e.getApplicationContext();
}
Event Trigger
ContextRefreshedEvent refresh() / actuator refresh
ContextStartedEvent start() called
ContextStoppedEvent stop() called
ContextClosedEvent close() called

8. Implementing Graceful Shutdown

Example: Graceful shutdown with timeout

server:
  shutdown: graceful
spring:
  lifecycle:
    timeout-per-shutdown-phase: 30s
Effect Description
Stop accepting new requests Web server returns connections
Drain in-flight Waits up to timeout-per-shutdown-phase
Trigger SIGTERM, JVM hook, actuator /shutdown

9. Using Exit Codes (ExitCodeGenerator)

Example: Custom exit code with ExitCodeGenerator

@SpringBootApplication
public class App {
  public static void main(String[] args) {
    System.exit(SpringApplication.exit(SpringApplication.run(App.class, args),
      () -> 42));
  }
}
Element Use
ExitCodeGenerator Bean returning exit code
ExitCodeExceptionMapper Map exception → code
SpringApplication.exit() Compute aggregated exit code

10. Configuring Startup Actuator Endpoint

Property Value
management.endpoint.startup.enabled true
management.endpoints.web.exposure.include startup,health
spring.main.application-startup BufferingApplicationStartup(1024) in main

Example: Buffer startup steps for /actuator/startup

SpringApplication app = new SpringApplication(App.class);
app.setApplicationStartup(new BufferingApplicationStartup(2048));
app.run(args);