Spring Boot Startup Flow
Introduction
When you run SpringApplication.run(), Spring Boot prepares the environment, loads auto-configuration, creates the application context, starts the embedded web server, and publishes lifecycle events. Knowing this sequence helps you debug slow startup, missing beans, and failures that happen before the first HTTP request.
Prerequisites
Entry Point
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}SpringApplication.run roughly:
1. Create SpringApplication instance
2. Run listeners (StartupApplicationListener)
3. Prepare Environment (properties, profiles, env vars)
4. Print banner (optional)
5. Create ApplicationContext
6. Refresh context (bean registration)
7. Call runners (ApplicationRunner / CommandLineRunner)
8. Return started contextEnvironment Preparation
Sources merged (later overrides earlier):
| Source | Example |
|---|---|
application.properties / application.yml | server.port=8080 |
| Profile files | application-dev.yml |
| Environment variables | SERVER_PORT=9090 |
| Command line args | --server.port=9090 |
Active profiles:
spring:
profiles:
active: devOr --spring.profiles.active=prod.
Context Refresh (Core)
AbstractApplicationContext.refresh():
- Parse configuration classes (
@Configuration,@ComponentScan) - Invoke
BeanFactoryPostProcessor - Register bean definitions
- Instantiate singleton beans
- Run
BeanPostProcessorchain (AOP proxies,@Autowiredinjection) - Publish
ContextRefreshedEvent
Auto-configuration classes participate during bean definition loading—conditions evaluated before creating expensive beans.
Embedded Web Server Start
For servlet apps (spring-boot-starter-web):
ServletWebServerFactory bean created (Tomcat)
↓
WebServer started on server.port
↓
DispatcherServlet registered
↓
Log: "Tomcat started on port(s): 8080"Reactive (WebFlux) uses NettyReactiveWebServerFactory instead—different stack, same startup idea.
ApplicationRunner Hooks
Run code after context is up:
@Component
public class StartupValidator implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
// verify external dependency, warm cache
}
}CommandLineRunner similar—raw String[] args.
Order multiple runners with @Order(1).
Lifecycle Events
| Event | When |
|---|---|
ApplicationStartingEvent | Before context |
ApplicationEnvironmentPreparedEvent | Environment ready |
ContextRefreshedEvent | Beans initialized |
ApplicationReadyEvent | App accepting traffic |
ContextClosedEvent | Shutdown |
Listen for metrics or readiness checks:
@Component
public class ReadyListener {
@EventListener
public void onReady(ApplicationReadyEvent event) {
// app fully started
}
}Startup Failure Debugging
Common log sections:
APPLICATION FAILED TO START
Description: ...
Action: ...Steps:
- Read root cause at bottom of stack trace
- Run with
--debugfor condition report - Check missing property:
Could not resolve placeholder - Check port bind:
Port 8080 already in use - Check DB on startup if
ddl-auto=validatefails
Disable fail-fast datasource (dev only):
spring:
datasource:
hikari:
initialization-fail-timeout: -1Not recommended for prod—fix connectivity instead.
Slow Startup Tips
| Tip | Effect |
|---|---|
| Lazy-init non-critical beans | Faster first context (delay later) |
| Reduce classpath scanning | Narrow @ComponentScan |
| Disable unused auto-config | Less bean work |
| AOT / native image | Advanced—later chapter |
Measure:
spring.main.log-startup-info=trueBoot 3 logs startup steps with timings when enabled.
Graceful Shutdown
server:
shutdown: graceful
spring:
lifecycle:
timeout-per-shutdown-phase: 30sIn-flight requests finish before JVM exits—important for Kubernetes rolling updates.
FAQ
Started but 404 on endpoint?
Controller outside component scan package—move class or adjust scan.
Two ApplicationContext?
Parent/child rare in Boot apps—usually one context in simple apps.
Bean created too early?
Depends on injection graph—use @DependsOn sparingly.
Fail on missing optional service?
Use @ConditionalOnProperty for optional integrations.
main runs twice in IDE?
Debug "Spring Boot" + "Application" duplicate run configs—pick one.
Next topic?
Redis, Security, Actuator—scenario integration chapters follow.