Lifecycle
SpringApplication, startup process, ApplicationRunner, CommandLineRunner
Lifecycle
1. Definition
The Spring Boot application lifecycle is the process from the SpringApplication.run() call to application shutdown. This includes creating the ApplicationContext, auto-configuration, bean initialization, starting the embedded server, and graceful shutdown.
Spring Boot provides numerous extension points (hooks) at various lifecycle phases:
- ApplicationRunner / CommandLineRunner â logic after startup
- ApplicationEvent system â event-driven integration
- SmartLifecycle â fine-grained start/stop ordering
- @PreDestroy / DisposableBean â shutdown logic
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication.run(MyApp.class, args);
}
}
2. Core Concepts
SpringApplication startup process
SpringApplication.run() executes the following steps:
- Create SpringApplication instance â detect application type (Servlet, Reactive, None)
- Notify SpringApplicationRunListeners â
startingevent - Prepare Environment â load property sources, activate profiles
- Print Banner â the Spring Boot banner
- Create ApplicationContext â according to the context type
- Context refresh â load bean definitions, auto-configuration, bean initialization
- Run Runners â ApplicationRunner, CommandLineRunner
- Done â
startedârunningevent
ApplicationRunner vs CommandLineRunner
@Component
public class MyAppRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// ApplicationArguments â structured argument access
boolean debug = args.containsOption("debug");
List<String> files = args.getNonOptionArgs();
}
}
@Component
public class MyCmdRunner implements CommandLineRunner {
@Override
public void run(String... args) {
// Raw String array â simple arguments
System.out.println("Arguments: " + Arrays.toString(args));
}
}
Application Events
| Event | When? |
|---|---|
| ApplicationStartingEvent | Beginning of SpringApplication.run() |
| ApplicationEnvironmentPreparedEvent | Environment ready, context not yet created |
| ApplicationContextInitializedEvent | Context created, beans not yet loaded |
| ApplicationPreparedEvent | Bean definitions loaded, before refresh |
| ApplicationStartedEvent | Context refresh done, before runners |
| ApplicationReadyEvent | Runners completed, application ready |
| ApplicationFailedEvent | Error occurred during startup |
Shutdown
Spring Boot supports graceful shutdown:
# Graceful shutdown
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s
3. Practical Usage
Post-startup initialization
@Component
@Order(1) // order: lower = earlier
public class DatabaseInitializer implements ApplicationRunner {
private final DataSource dataSource;
public DatabaseInitializer(DataSource dataSource) {
this.dataSource = dataSource;
}
@Override
public void run(ApplicationArguments args) {
// Database schema initialization
// The context is fully initialized
}
}
@Component
@Order(2)
public class CacheWarmUp implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// Cache warm-up after database initialization
}
}
Event listeners
@Component
public class StartupListener {
@EventListener(ApplicationReadyEvent.class)
public void onReady() {
// Application is fully ready
System.out.println("Application is ready!");
}
@EventListener(ApplicationStartedEvent.class)
public void onStarted() {
// Context refresh done, runners haven't executed yet
}
}
Early event listeners (spring.factories)
ApplicationStartingEvent and ApplicationEnvironmentPreparedEvent occur before context creation, so they cannot be registered as @Component:
public class EarlyEventListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) {
System.out.println("Application starting...");
}
}
Registration:
# META-INF/spring.factories
org.springframework.context.ApplicationListener=\
com.example.EarlyEventListener
Customizing SpringApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApp.class);
app.setBannerMode(Banner.Mode.OFF);
app.setAdditionalProfiles("metrics");
app.setDefaultProperties(Map.of("server.port", "9090"));
app.run(args);
}
}
4. Code Examples
SmartLifecycle implementation
@Component
public class MessageConsumer implements SmartLifecycle {
private volatile boolean running = false;
@Override
public void start() {
running = true;
// Start Kafka/RabbitMQ consumer
}
@Override
public void stop() {
running = false;
// Stop consumer
}
@Override
public boolean isRunning() {
return running;
}
@Override
public int getPhase() {
return Integer.MAX_VALUE; // starts last, stops first
}
@Override
public boolean isAutoStartup() {
return true;
}
}
Bean lifecycle annotations
@Component
public class ConnectionPool {
private HikariDataSource dataSource;
@PostConstruct
public void init() {
// After bean creation â initialization
dataSource = new HikariDataSource();
dataSource.setJdbcUrl("jdbc:postgresql://localhost/mydb");
}
@PreDestroy
public void cleanup() {
// On application shutdown â resource cleanup
if (dataSource != null) {
dataSource.close();
}
}
}
SpringApplicationBuilder (fluent API)
public class MyApp {
public static void main(String[] args) {
new SpringApplicationBuilder(MyApp.class)
.bannerMode(Banner.Mode.LOG)
.profiles("production")
.properties("server.port=8443")
.listeners(new EarlyEventListener())
.run(args);
}
}
Startup actuator (Boot 3.x)
management.endpoint.startup.enabled=true
management.endpoints.web.exposure.include=startup
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApp.class);
app.setApplicationStartup(new BufferingApplicationStartup(10000));
app.run(args);
}
}
5. Trade-offs
| Aspect | ApplicationRunner | CommandLineRunner |
|---|---|---|
| Arguments | ApplicationArguments (structured) | String[] (raw) |
| Option parsing | Built-in (--key=value) |
Manual parsing |
| Use case | Complex arguments | Simple scripts |
| Aspect | @PostConstruct | ApplicationRunner |
|---|---|---|
| Execution time | During bean creation | After full context ready |
| Other beans | Not guaranteed all ready | All initialized |
| Scope | Single bean | Application-level |
| Aspect | @EventListener | ApplicationListener |
|---|---|---|
| Registration | @Component (in context) | spring.factories (early) |
| Early events | â Not accessible | â Accessible |
| Simplicity | â Annotation-based | â Interface implementation |
6. Common Mistakes
â Relying on other beans in @PostConstruct
@Component
public class ReportService {
@Autowired
private UserRepository userRepository;
@PostConstruct
public void init() {
// RISKY: UserRepository bean is initialized,
// but the full context (e.g., transaction manager) may not be
long count = userRepository.count();
}
}
â Use ApplicationRunner instead
@Component
public class ReportService implements ApplicationRunner {
private final UserRepository userRepository;
public ReportService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public void run(ApplicationArguments args) {
// SAFE: the full context is initialized
long count = userRepository.count();
}
}
â Early event as @Component
// WRONG: ApplicationStartingEvent occurs BEFORE context creation
@Component // â will NOT receive the event!
public class MyListener implements ApplicationListener<ApplicationStartingEvent> {
@Override
public void onApplicationEvent(ApplicationStartingEvent event) { }
}
â Register in spring.factories
# META-INF/spring.factories
org.springframework.context.ApplicationListener=\
com.example.MyListener
â Missing runner ordering
When multiple Runners depend on each other but lack @Order â random execution order.
@Component
@Order(1) // â ALWAYS set order when dependencies exist
public class FirstRunner implements ApplicationRunner { ... }
@Component
@Order(2)
public class SecondRunner implements ApplicationRunner { ... }
7. Deep Dive
Complete startup sequence
1. main() calls SpringApplication.run()
2. SpringApplication instance created
3. SpringApplicationRunListeners.starting()
4. Environment preparation (property sources, profiles)
5. Banner printing
6. ApplicationContext creation (type: Servlet/Reactive/None)
7. Context refresh:
a. BeanFactory preparation
b. BeanDefinition loading
c. BeanFactoryPostProcessor execution
d. Bean instantiation + dependency injection
e. BeanPostProcessor (AOP proxy, @PostConstruct)
f. SmartLifecycle.start()
8. ApplicationStartedEvent
9. ApplicationRunner / CommandLineRunner execution
10. ApplicationReadyEvent
11. Application running (accepting requests)
Graceful shutdown details
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s
Graceful shutdown process:
- Stop accepting new requests
- Wait for in-flight requests (up to timeout)
- SmartLifecycle.stop() â reverse phase order
- @PreDestroy / DisposableBean.destroy()
- ApplicationContext close
Startup performance measurement
@SpringBootApplication
public class MyApp {
public static void main(String[] args) {
SpringApplication app = new SpringApplication(MyApp.class);
// Boot 3.x: measure startup steps
app.setApplicationStartup(new BufferingApplicationStartup(10000));
app.run(args);
}
}
// GET /actuator/startup â JSON with detailed timing
Liveness and Readiness probes
# Kubernetes probes
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
- Liveness: is the application running (not deadlocked)
- Readiness: is it ready to accept requests (runners completed)
8. Interview Questions
What is the difference between ApplicationRunner and CommandLineRunner? ApplicationRunner: ApplicationArguments (structured, option parsing). CommandLineRunner: String[] (raw). Both run after full context initialization.
What is the Spring Boot startup order? Environment â Banner â Context create â Refresh (beans) â Started event â Runners â Ready event.
What is the difference between @PostConstruct and ApplicationRunner? @PostConstruct: runs during individual bean creation (not guaranteed all other beans are ready). ApplicationRunner: runs after the full context is initialized.
How do you listen to early events? Register the ApplicationListener in spring.factories, because events before context creation are not accessible via @Component.
What is graceful shutdown? Stop accepting new requests, wait for in-flight ones, SmartLifecycle.stop(), @PreDestroy, context close.
What is SmartLifecycle? Interface for fine-grained start/stop ordering. The phase value determines the order. Lower phase = starts earlier, stops later.
How do you measure startup performance? BufferingApplicationStartup + /actuator/startup endpoint. Boot 3.x feature.
9. Glossary
| Term | Meaning |
|---|---|
| SpringApplication | Spring Boot application entry point and bootstrap class |
| ApplicationRunner | Post-startup logic execution (ApplicationArguments) |
| CommandLineRunner | Post-startup logic execution (String[]) |
| ApplicationEvent | Application lifecycle events |
| ApplicationReadyEvent | Application fully ready (runners completed) |
| SmartLifecycle | Fine-grained start/stop ordering interface |
| @PostConstruct | Post-bean-creation initialization |
| @PreDestroy | Pre-shutdown cleanup |
| Graceful shutdown | Completing requests before shutdown |
| BufferingApplicationStartup | Startup performance measurer (Boot 3.x) |
10. Cheatsheet
Startup order:
main() â SpringApplication.run()
â Environment â Banner â Context create
â Refresh (beans) â SmartLifecycle.start()
â ApplicationStartedEvent
â ApplicationRunner / CommandLineRunner
â ApplicationReadyEvent â application running
Shutdown order:
SIGTERM â stop accepting new requests
â wait for in-flight requests
â SmartLifecycle.stop() (reverse phase)
â @PreDestroy / DisposableBean
â Context close
// ApplicationRunner (structured arguments)
@Component @Order(1)
public class MyRunner implements ApplicationRunner {
public void run(ApplicationArguments args) { }
}
// CommandLineRunner (raw String[])
@Component @Order(2)
public class MyCmdRunner implements CommandLineRunner {
public void run(String... args) { }
}
// Event listener
@EventListener(ApplicationReadyEvent.class)
public void onReady() { }
// SmartLifecycle (start/stop ordering)
implements SmartLifecycle { getPhase(); start(); stop(); }
# Graceful shutdown
server.shutdown=graceful
spring.lifecycle.timeout-per-shutdown-phase=30s
# Kubernetes probes
management.endpoint.health.probes.enabled=true
management.health.livenessState.enabled=true
management.health.readinessState.enabled=true
# Startup performance measurement
management.endpoint.startup.enabled=true
đź Games
10 questions