Understanding Application Lifecycle
1. Understanding Spring Boot Startup Sequence
Boot Startup Phases
- Bootstrap context (if Spring Cloud)
- Create
SpringApplication, deduce web type (servlet/reactive/none) - Run
ApplicationContextInitializers - Prepare
Environment(load profiles, properties) - Print banner
- Create
ApplicationContext - Apply
BeanFactoryPostProcessors &BeanPostProcessors - Refresh context → instantiate singletons
- Call
ApplicationRunner/CommandLineRunner - 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 |