How a Spring Boot Application Works (Under the Hood)
1) Launch & bootstrap
-
main()
callsSpringApplication.run(App.class, args)
. -
SpringApplication decides the app type (Servlet/WebFlux/none), sets up Bootstrap logging, loads
ApplicationContext
type, banner, listeners, and default converters.
2) Create the ApplicationContext
- It creates an IoC container (
AnnotationConfigApplicationContext
for non-web,ServletWebServerApplicationContext
for MVC, orReactiveWebServerApplicationContext
for WebFlux). -
Environment (profiles, properties) is prepared: command-line args,
application.yml/properties
, OS env vars, system props, profile-specific files (application-dev.yml
), and anyPropertySource
you add.
3) Auto-configuration & component scanning
-
@SpringBootApplication
=@Configuration
+@EnableAutoConfiguration
+@ComponentScan
. -
Component scan finds your
@Component
,@Service
,@Repository
,@Controller/@RestController
,@Configuration
classes. -
Auto-configuration imports a curated set of
@Configuration
classes based on the classpath & Environment (e.g., ifspring-boot-starter-web
is present, it configures Spring MVC, Jackson, an embedded server, etc.).- Runs via conditions:
@ConditionalOnClass
,@ConditionalOnMissingBean
,@ConditionalOnProperty
, etc. - Since Spring Boot 3, auto-config classes are listed in
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
(replacing oldspring.factories
approach).
- Runs via conditions:
4) Bean creation & lifecycle
- The container registers bean definitions (from your app + auto-config) and then instantiates beans in dependency order.
- Lifecycle hooks apply: constructor injection â
@PostConstruct
(orInitializingBean.afterPropertiesSet
) âBeanPostProcessors
(AOP proxies created here) â ready. - If a bean fails its condition, Boot backs off so your custom bean wins (
@ConditionalOnMissingBean
).
5) Externalized configuration binding
- Boot binds properties to strongly typed configs using
@ConfigurationProperties
(via the Binder API) and also to@Value
fields. -
Relaxed binding:
my.service-timeout
,my.serviceTimeout
,MY_SERVICE_TIMEOUT
all map tomy.service-timeout
.
Short example:
@ConfigurationProperties(prefix="app.greeting")
public record GreetingProps(String message, int repeat) {}
6) Web stack setup (Servlet or Reactive)
Servlet/MVC path
13. Boot starts an embedded server (Tomcat/Jetty/Undertow) via ServletWebServerFactory
.
14. Registers DispatcherServlet
, Filters, Servlets, and MVC infrastructure (HandlerMappings, HandlerAdapters, MessageConverters, ExceptionResolvers).
15. An HTTP request flows:
- Server â Filter chain â
DispatcherServlet
- Choose handler (controller) via HandlerMapping
- Invoke controller method (argument resolvers bind path/query/body)
- Return value written via HttpMessageConverters (e.g., JSON via Jackson)
- Exception handling via
@ControllerAdvice
/ resolvers - Response â Filters â client
Reactive/WebFlux path
16. Starts Netty (via Reactor Netty
), sets up DispatcherHandler
, HandlerMappings/Adapters/ResultHandlers, and encoders/decoders for reactive types (Mono
/Flux
).
7) Actuator, metrics, health
-
If
spring-boot-starter-actuator
is present, Boot auto-configures /actuator endpoints (health, metrics, info), Micrometer registry, and health contributors (DB, disk, etc.). Secure & expose endpoints based on properties.
8) Application events & runners
- Boot publishes lifecycle events (ApplicationStarting â EnvironmentPrepared â Prepared â Started â Ready).
- Your
CommandLineRunner
/ApplicationRunner
beans run after context is ready (great for seeding data, warmups).
@SpringBootApplication
@EnableConfigurationProperties(GreetingProps.class)
public class App {
public static void main(String[] args) { SpringApplication.run(App.class, args); }
@Bean CommandLineRunner runner(GreetingProps p) {
return args -> { for (int i=0; i<p.repeat(); i++) System.out.println(p.message()); };
}
}
9) Packaging & execution model
- Boot builds a fat/uber JAR with a custom Spring Boot Loader; you can
java -jar app.jar
. It sets up a layered classloader so dependencies and app classes are isolated (helps with Docker layering too).
10) Profiles & environment-specific beans
- Use
@Profile("dev")
/spring.profiles.active=prod
to switch beans and properties per environment. Conditions can also check Cloud platforms, presence of libs, or flags.
11) Security (if added)
-
Adding
spring-boot-starter-security
auto-configures a security filter chain with sensible defaults (CSRF, basic login) and you customize viaSecurityFilterChain
beans.
12) AOT & native images (optional)
- With Spring AOT & GraalVM Native, Boot can generate ahead-of-time hints (reflection, proxies) to build native binaries for super-fast startup & low memory.
TL;DR sequence
main()
â SpringApplication
prepares env â create ApplicationContext
â component scan + conditional auto-config â bind externalized config â create/proxy beans â start embedded server (or Netty) â register dispatch layer â run runners â Ready.