Spring Boot Deep Dive: Auto-Configuration, Startup Flow & Source Code Analysis
This comprehensive guide dissects Spring Boot's core mechanisms including auto-configuration internals, the nine-step startup process from main() to port binding, embedded Tomcat initialization, configuration binding, and fat JAR loading, with source code references and a structured learning path for mastering the framework.
1. What Is Spring Boot: Positioning & Version Evolution
Spring Boot is not a new framework but a "assembler + runtime" layer atop Spring Framework . It does four things: aligns dependency versions (BOM), automates common configuration (auto-configuration), embeds the servlet container (embedded Tomcat), and bakes in operational capabilities (Actuator). Spring solves "how to organize objects"; Spring Boot solves "how to get this stack running."
Key boundary: Boot does not replace Spring (IoC, AOP, MVC remain), and using Boot does not excuse ignorance of Spring's container model — auto-configuration's endpoint is BeanDefinition .
1.2 Evolution Timeline
2014 : Spring Boot 1.0 — "convention over configuration": one main method, one JAR, zero XML.
2018 : Spring Boot 2.0 on Spring 5 — WebFlux reactive stack, Actuator rewrite, Micrometer metrics, JDK 8 baseline.
2022 : Spring Boot 3.0 — "generational" upgrade: JDK 17 baseline, javax → jakarta namespace, AOT & GraalVM native images, unified Observability via Observation API.
3.2/3.3/3.4 : Virtual threads (JDK 21), CRaC fast startup, Docker Compose & Testcontainers dev-time support, structured logging, RestClient & HTTP Interface.
1.3 Critical 2.x vs 3.x Differences
Namespace migration : javax.servlet, javax.validation → jakarta.*; third-party libraries (old MyBatis, Shiro, Swagger) must upgrade in lockstep.
Auto-configuration registration file changed : META-INF/spring.factories no longer carries auto-configuration; replaced by
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports(one class name per line).
AOT & native images : New spring-aot plugin generates bean registration & reflection hints at build time; GraalVM native image startup reaches hundreds of milliseconds, trade-off: slower build, must handle reflection & dynamic proxies.
Observability unified : Observation abstraction unifies metrics & tracing, replacing scattered Micrometer + Sleuth; Sleuth stopped evolving in 3.x.
Other : Removed parts of spring-boot-properties-migrator, default allow-bean-definition-overriding=false, support for ProblemDetail (RFC 7807) unified error responses.
1.4 Problems Solved
Configuration hell : Hundreds of lines of XML/JavaConfig → one spring-boot-starter-web + one-line launcher.
Dependency version conflicts : Manual trial-and-error for Spring, Jackson, Tomcat, Hibernate versions → parent POM manages, starters transmit aligned versions.
Long deployment chain : Build WAR, install Tomcat, configure context path → embedded container, java -jar starts instantly, naturally fits containerization.
Ops invisibility : Health checks, metrics, config inspection all DIY → Actuator provides standard endpoints: health, metrics, env, threaddump.
Critical boundary : Spring Boot and Spring Cloud are not the same layer. Boot handles "how a single service starts fast"; Cloud handles "how multiple services collaborate" (discovery, config center, circuit breaker, gateway). Upgrading Boot 3 often requires Cloud 2022.x+; strict version mapping exists.
2. Technical Analysis: Three Core Capabilities, Auto-Configuration, Configuration System
2.1 Three Capabilities & One Main Line
Boot's capabilities condense to three, but share a common main line: turn "config you'd hand-write" into "conditionally judged BeanDefinition" .
① Auto-configuration : Based on classpath content & your config, decides whether to register a bean. Mechanism: @EnableAutoConfiguration + conditional annotations.
② Starters : Almost no code, just a "dependency manifest": pulling one brings a version-aligned jar set. Real config lives in corresponding autoconfigure module.
③ Embedded container : Tomcat/Jetty/Undertow pulled as ordinary jars, created & started by WebServerFactory during refresh phase — no external container needed.
The main line always ends at Spring's BeanFactory. Key insight: Auto-configuration = before container refresh, "conditionally" stuffing a batch of definitions into BeanDefinitionMap .
2.2 @SpringBootApplication Deconstructed
This annotation combines three, none optional:
@SpringBootApplication
= @SpringBootConfiguration
(essence is @Configuration)
+ @EnableAutoConfiguration
(enables auto-configuration)
+ @ComponentScan
(scans launch class package & sub-packages)@SpringBootConfiguration : Marks a config class (CGLIB-enhanceable), lets test framework locate launch class.
@EnableAutoConfiguration : Via @Import(AutoConfigurationImportSelector.class) bulk-imports candidate config classes; itself registers no beans, only "selects".
@ComponentScan : Scans launch class package & sub-packages . This is why controllers must reside in same or sub-package — the #1 cause of newbie 404s.
2.3 Complete Auto-Configuration Mechanism (Five Steps)
Collect candidates : Read all candidate config class names from every jar's AutoConfiguration.imports (2.x used spring.factories).
Deduplicate & exclude : Remove duplicates, then drop classes specified in @EnableAutoConfiguration(exclude=...) or spring.autoconfigure.exclude.
Fast filtering : Use AutoConfigurationImportFilter ( OnClassCondition,
OnWebApplicationCondition</strong>) to batch-filter out "obviously unsatisfied" items <strong>without loading classes</strong> — key startup performance optimization.</li><li><strong>Precise condition evaluation</strong>: Parse remaining candidates one by one, evaluating <code>@ConditionalOnClass, @ConditionalOnMissingBean, @ConditionalOnProperty, etc.
Sort & register : Order by @AutoConfigureOrder, @AutoConfigureBefore, @AutoConfigureAfter; finally parsed as config classes by container, producing BeanDefinitions.
Why step 5 order matters : Many auto-config classes use @ConditionalOnMissingBean — "you register first, I back off". Wrong order → your custom bean gets overridden by default config.
2.4 Conditional Annotation Family (Seven Common)
@ConditionalOnClass/ @ConditionalOnMissingClass: Class present on classpath — basis of "add dependency, works instantly". @ConditionalOnBean / @ConditionalOnMissingBean: Bean present in container. Latter is key to "default config yields to user config"; reliable only inside auto-configuration classes , ordinary config classes affected by parse order. @ConditionalOnProperty: Toggle by config (name/havingValue/matchIfMissing) — most used for feature flags. @ConditionalOnWebApplication / OnNotWebApplication: Activate by app type (SERVLET/REACTIVE/NONE) — prevents web config polluting batch apps. @ConditionalOnResource / OnExpression: Activate by resource existence or SpEL result.
2.5 Configuration System & Priority
"Where config comes from, who overrides whom" is a frequent production blind spot. High-to-low priority mainline:
1. Command-line args --server.port=9090
2. System props / env vars SPRING_APPLICATION_JSON
3. External config files jar sibling config/ dir
4. Jar-internal config/ & classpath root
5. @PropertySource files
6. Default values setDefaultPropertiesTwo must-know rules:
Profile overlay rule : Load application.yml first, then overlay application-{profile}.yml; multiple profiles → last activated wins , not "merge & equal rights".
@Value vs @ConfigurationProperties : Former injects single, no relaxed binding/validation/complex structures; latter batch-binds, supports relaxed binding ( my-app.name matches myApp.name / MY_APP_NAME), can add @Validated — production projects should prefer the latter .
2.6 Embedded Container & Observability
Embedded container value isn't just "saves a Tomcat install" but brings web server lifecycle under IoC container management — it reads config, supports graceful shutdown, closes with context.
Container choice : Default Tomcat; spring-boot-starter-jetty / undertow swappable (must exclude tomcat). High concurrency → Undertow lower memory.
Why WAR still supported : Extend SpringBootServletInitializer + change packaging → external deploy, but loses "embedded container starts with context" advantage; generally only for migration.
Observability : Actuator endpoints + Micrometer metrics + Observation tracing. Production must enable health (K8s probe), metrics, prometheus; other endpoints default to health only — never expose all .
3. Core Flow Analysis: From main() to Port Listening
3.1 SpringApplication.run Nine Steps
Main backbone — remember order, not every detail:
Construct SpringApplication : Infer app type (NONE/SERVLET/REACTIVE), load ApplicationContextInitializer & ApplicationListener (from spring.factories).
Record start time, start stopwatch : Generate StartupInfo for later "Started in x seconds" log.
prepareEnvironment : Create Environment, trigger EnvironmentPostProcessor, load application.yml & profiles, publish environment-ready event.
createApplicationContext : Reflectively instantiate AnnotationConfigServletWebServerApplicationContext etc. per app type.
prepareContext : Inject environment, beanNameGenerator, resourceLoader into context; execute all Initializers; register primary config class (launch class itself).
refreshContext most critical step : Call AbstractApplicationContext.refresh() completing 12 sub-steps; onRefresh starts Tomcat.
afterRefresh : Reserved extension point, default no-op (2.x+ deprecated tendency, ignorable).
stopWatch.stop & publish started event : Print startup duration log; ApplicationRunner & CommandLineRunner invoked here.
Publish ready event : Port now listening, all beans ready; ApplicationReadyEvent is safest "post-startup" entry.
Note division between steps 5 & 6 : prepareContext only does "prep work" (no business bean creation); actual singleton bean instantiation happens in refresh's finishBeanFactoryInitialization.
3.2 refresh() 12 Steps & Boot's Intervention Points
01 prepareRefresh record start time, validate required props
02 obtainFreshBeanFactory create/reuse BeanFactory
03 prepareBeanFactory register resolvers, ignore interfaces, BPP
04 postProcessBeanFactory subclass extension (web container intervenes here)
05 invokeBeanFactoryPostProcessors 【auto-configuration takes effect here】
06 registerBeanPostProcessors register BeanPostProcessor
07 initMessageSource i18n
08 initApplicationEventMulticaster event broadcaster
09 onRefresh 【create & start embedded Tomcat】
10 registerListeners
11 finishBeanFactoryInitialization 【instantiate all non-lazy singletons】
12 finishRefresh publish events, start LifecycleFor Boot only four nodes matter: 05 (auto-config), 09 (start container), 11 (create beans), 12 (publish events) . Step 05 batch-imports config classes because ConfigurationClassPostProcessor (a BeanFactoryPostProcessor) parses all @Import there.
3.3 Embedded Tomcat Startup Sequence
"Who starts Tomcat?" Answer lies in onRefresh: ServletWebServerApplicationContext.onRefresh() calls createWebServer().
Fetch ServletWebServerFactory from container (Tomcat → TomcatServletWebServerFactory, provided by ServletWebServerFactoryAutoConfiguration). getWebServer() creates Tomcat instance → sets Connector (port, protocol) → creates TomcatEmbeddedContext.
Register DispatcherServlet as ServletRegistrationBean into Context (mapped to /). TomcatWebServer constructor calls initialize() → tomcat.start() binds port; if port occupied, throws PortInUseException.
Port truly starts accepting requests before all singleton beans finish (refresh step 09 precedes 11) → during startup may see "port open but API 503".
3.4 Configuration Loading Flow
prepareEnvironment()
└─ EnvironmentPostProcessorListener
└─ ConfigDataEnvironmentPostProcessor
├─ ConfigDataLocationResolver
│ resolves classpath / file / optional
├─ ConfigDataLoader
│ reads properties / yaml
└─ merges by profile into PropertySource
Binding to objects:
ConfigurationPropertiesBindingPostProcessor
└─ Binder.bind()
relaxed binding + type conversion + validationImportant 3.x change: Config loading unified into ConfigData API , no longer via ConfigFileApplicationListener (2.x old entry, removed in 3.x). So online "custom config file loading" tutorials likely break on 3.x.
3.5 Graceful Shutdown
Receive SIGTERM (or call actuator/shutdown) → trigger ApplicationShutdownHook.
Container close → LifecycleProcessor.onClose() stops all SmartLifecycle (reverse phase order).
Web server stops accepting new requests, waits for in-flight requests to complete (bound by spring.lifecycle.timeout-per-shutdown-phase).
Destroy beans sequentially ( @PreDestroy / DisposableBean), close thread pools, data sources, MQ consumers.
Default is immediate shutdown ; must explicitly enable: server.shutdown=graceful. Critical for K8s rolling deploys — otherwise each release interrupts in-flight requests, manifesting as "sporadic 502 during deploy".
3.6 How Fat JAR Gets Launched
app.jar
├─ META-INF/MANIFEST.MF
│ Main-Class: JarLauncher
│ Start-Class: your launch class
├─ org/springframework/boot/loader/
├─ BOOT-INF/classes/ your classes
└─ BOOT-INF/lib/ dependency jars
java -jar execution chain:
JarLauncher.main()
└─ create LaunchedURLClassLoader (supports nested jars)
└─ reflectively invoke Start-Class.main()Key point: Standard JVM cannot load jars inside a jar , so Boot implements LaunchedURLClassLoader treating BOOT-INF/lib/xxx.jar!/ nested paths as URLs. Explains why some deps run in IDE but throw ClassNotFoundException after JAR packaging — likely bypassed this classloader (custom URLClassLoader or reflective loading).
4. Core Source Code Analysis: Nine Key Chains
4.1 Source Reading Strategy
Boot source smaller than Spring Framework but must read right places. Three modules division:
spring-boot : Core runtime: SpringApplication, Environment, config loading, logging init. Read here for startup flow.
spring-boot-autoconfigure : All official auto-config classes + AutoConfiguration.imports. Read here for auto-config; focus on 3–5 representative classes.
spring-boot-loader : Packaging & classloading: JarLauncher, LaunchedURLClassLoader. Small codebase, good first stop for source reading.
Suggested order: loader (simple) → SpringApplication.run (backbone) → autoconfigure (broad but shallow per point) . Don't dive into autoconfigure first — hundreds of config classes, easy to drown.
4.2 run() Backbone Source
// SpringApplication.java
public ConfigurableApplicationContext
run(String... args) {
StartupInfo info = StartupInfo.get(args);
SpringApplicationRunListeners
listeners = getRunListeners(args);
listeners.starting(info);
ApplicationArguments arguments =
new DefaultApplicationArguments(args);
ConfigurableEnvironment environment =
prepareEnvironment(listeners, arguments);
context = createApplicationContext();
prepareContext(context, environment,
listeners, arguments);
refreshContext(context); // 12 steps
afterRefresh(context, arguments);
listeners.started(context,
info.getTimeTaken());
callRunners(context, arguments);
listeners.ready(context,
info.getTimeTaken());
return context;
}Note SpringApplicationRunListeners: aggregates all listeners into a facade, broadcasts events at each phase (starting/environmentPrepared/contextPrepared/contextLoaded/started/ready). This event system is Boot's own extension mechanism , not Spring's ApplicationEvent — latter only has broadcast capability after container refresh.
4.3 createApplicationContext Type Inference
// WebApplicationType.deduceFromClasspath()
// Rules (strongest to weakest):
// 1. Has WebFlux DispatcherHandler
// and no MVC DispatcherServlet
// → REACTIVE
// 2. Has Servlet class
// and has WebApplicationContext
// → SERVLET
// 3. Others → NONEExplains classic phenomenon: including both web and webflux starters → app starts in SERVLET mode (rule 2 beats rule 1), causing WebFlux config to not activate. To use reactive must exclude spring-boot-starter-web.
4.4 Auto-Configuration Entry: getAutoConfigurationEntry
// AutoConfigurationImportSelector
protected AutoConfigurationEntry
getAutoConfigurationEntry(
AnnotationMetadata meta,
AnnotationAttributes attrs) {
if (!isEnabled(meta, attrs)) return EMPTY;
// ① read all jars' imports, deduplicate
List<String> candidates =
getCandidateConfigurations(meta, attrs);
// ② remove excludes
Set<String> exclusions =
getExclusions(meta, attrs, candidates);
candidates.removeAll(exclusions);
// ③ batch condition filtering
candidates = getConfigurationClassFilter()
.filter(candidates);
// ④ sort & return
return new AutoConfigurationEntry(
candidates, exclusions);
}Step ① in 3.x done by ImportCandidates.load(), reading that long-named file:
META-INF/spring/
org.springframework.boot.autoconfigure
.AutoConfiguration.imports
File content: one fully-qualified class per line
(no key, no equals)
org.springframework.boot.autoconfigure
.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure
.jdbc.DataSourceAutoConfigurationStep ③ is performance-critical. Uses AutoConfigurationMetadata (build-time generated metadata) to evaluate conditions, no class loading needed to reject most candidates . Explains why Boot pulls hundreds of auto-config classes yet startup adds only hundreds of milliseconds.
4.5 Typical Auto-Configuration Class Structure
All official auto-config classes follow this pattern; understand one, understand a swath:
@AutoConfiguration
@ConditionalOnClass(DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@EnableConfigurationProperties(
DataSourceProperties.class)
public class DataSourceAutoConfiguration {
@Bean
@ConditionalOnMissingBean
public DataSource dataSource(
DataSourceProperties props) {
return props
.initializeDataSourceBuilder()
.build();
}
}Three-layer defense worth noting: class-level condition (whether whole config class activates), method-level condition (whether single bean registers), properties class handles binding . To override default behavior, safest isn't exclude but declare a same-type bean yourself — because @ConditionalOnMissingBean yields.
4.6 onRefresh & createWebServer
// ServletWebServerApplicationContext
protected void onRefresh() {
super.onRefresh();
try {
createWebServer();
} catch (Throwable ex) {
throw new ApplicationContextException(
"Unable to start web server", ex);
}
}
private void createWebServer() {
ServletWebServerFactory factory =
getWebServerFactory();
this.webServer = factory.getWebServer(
getSelfInitializer());
} getWebServerFactory()allows exactly one ServletWebServerFactory in container; multiple → immediate exception. So when customizing container, must first exclude default tomcat starter — root cause of "switch to Jetty, startup throws multiple factories".
4.7 Configuration Binding: What Binder Does
// ConfigurationPropertiesBindingPostProcessor
// triggers before bean initialization
// (postProcessBeforeInitialization)
public Object postProcessBeforeInitialization(
Object bean, String name) {
...
bind(annotation.prefix(), bean);
// → Binder.bind
...
}
Binder internals:
ConfigurationPropertySources
→ relaxed name matching
(kebab / camel / underscore)
→ ConversionService type conversion
→ constructor binding / JavaBean binding
→ validation (@Validated)Relaxed binding is the most practical feature here: config file writes my-app.max-pool-size, env var writes MYAPP_MAXPOOLSIZE, both bind to same field. Why K8s env var injection "just works".
4.8 Key Class Index Table
SpringApplication : Startup entry: run, prepareEnvironment, createApplicationContext, prepareContext.
AutoConfigurationImportSelector : Auto-config filter: getAutoConfigurationEntry, getCandidateConfigurations.
ConfigurationClassPostProcessor : At refresh step 05 parses all @Configuration / @Import / @ComponentScan — where auto-config actually lands.
ServletWebServerApplicationContext : Web context: onRefresh, createWebServer, getWebServerFactory.
TomcatServletWebServerFactory : Creates Tomcat: getWebServer, getTomcatWebServer, Connector & Context assembly.
ConfigDataEnvironmentPostProcessor : Config loading entry: resolves location, merges by profile, decides priority.
Binder / ConfigurationPropertiesBindingPostProcessor : Property binding: relaxed match, type conversion, validation.
JarLauncher / LaunchedURLClassLoader : Fat JAR bootstrap: registers nested jar URL protocol handler, then reflectively invokes Start-Class.
Final practical tip: To see which auto-configurations actually activated , start with --debug (or debug=true) — prints Positive matches / Negative matches tables; combine with Actuator's /actuator/conditions endpoint — faster than reading source to locate "why my config didn't activate".
5. Learning Path: Four Stages & Interview Checklist
5.1 Four-Stage Roadmap
Stage 1 · Can Use (1–2 weeks) : Goal: spin up CRUD service with DB, cache, API docs. Master starter inclusion, application.yml, profile switching, logging config, packaging & run. Graduation: from zero start a project, switch dev/prod configs, connect different DBs correctly.
Stage 2 · Understand Auto-Configuration (2–4 weeks) : Goal: explain @SpringBootApplication three layers, auto-config five steps, conditional annotation family, config priority chain; read Positive/Negative matches via --debug. Graduation: explain "I added this dependency, why this bean appeared", precisely locate why config didn't activate.
Stage 3 · Read Startup Source (1–2 months) : Goal: fully narrate every step from main to port listening; understand refresh 12 steps & Boot's four intervention points; locate root causes of slow/failed startup (bean circular deps, unsatisfied conditions, port conflict, missing config). Graduation: given a startup error stack trace, trace call stack to pinpoint which step, which condition, which bean failed.
Stage 4 · Build Wheels / Architect (3+ months) : Goal: write custom Starter (auto-config + conditions + properties + metadata); master Actuator & observability stack; understand AOT/native image/virtual thread applicability boundaries; do multi-service split & Cloud integration. Graduation: deliver a team-reusable Starter, consumer only needs dependency + three lines of config.
5.2 Ten-Step Source Reading Order
JarLauncher.main— entry simplicity builds confidence. SpringApplication constructor — how app type inferred. SpringApplication.run — nine-step backbone. prepareEnvironment — where config comes from. AbstractApplicationContext.refresh — 12 steps, focus 05/09/11. ConfigurationClassPostProcessor — how @Import expands. AutoConfigurationImportSelector — how candidates filtered. OnClassCondition — condition evaluation implementation. ServletWebServerApplicationContext.createWebServer — how Tomcat starts. Binder — how config binds to objects.
Three methodologies: 1) Keep debugger breakpoints throughout , at each run() step inspect BeanDefinition count changes; 2) Read with minimal project (only web starter) to eliminate business noise; 3) Ask "what problem does this step solve" before reading code — Boot code heavily templated dispatch logic, no need to read line-by-line.
5.3 High-Frequency Interview Questions (12)
Spring Boot vs Spring relationship? What exactly is "auto"?
@SpringBootApplication composed of which three annotations? Roles?
Complete auto-config flow? What did spring.factories become in 3.x?
Why does @ConditionalOnMissingBean "yield" to user config? Pitfalls?
At which step does embedded Tomcat start? Why port open but API unavailable?
Config priority order? Profile overlay: override or merge?
@Value vs @ConfigurationProperties difference? What is relaxed binding?
How to custom a Starter? Required files?
Why fat JAR runs via java -jar? How nested jars loaded?
How to enable graceful shutdown? What does it actually do?
AOT & native image principles & limits? When worth it?
What to change upgrading 2.x → 3.x? Hard blockers?
6. Best Practices & Common Pitfalls
6.1 Three Auto-Configuration Pitfalls
Wrong component scan range : Launch class in com.example.app, Controller in com.example.web → not scanned → 404. Fix: move launch class up or explicit @ComponentScan (common in multi-module).
Using exclude for everything : Excluding auto-config disables starter's other capabilities. More precise: declare same-type bean , or only disable corresponding property (e.g., spring.datasource.xxx).
@ConditionalOnMissingBean in ordinary config class : Reliability depends on parse order → "sometimes works, sometimes doesn't". Such conditions belong only in auto-configuration classes.
6.2 Diagnosing Slow Startup
① Locate : Enable ApplicationStartup ( BufferingApplicationStartup) with Actuator's /actuator/startup — see each phase duration, far better than guessing.
② Common causes : Lazy loading off → full instantiation; many @PostConstruct doing remote calls; over-scanning packages (including third-party); JPA full schema validation; connection pool init health-check timeout.
③ Remedies : spring.main.lazy-initialization=true (note: defers problem to first request), trim dependencies, CDS archives, native image if necessary.
6.3 Production Config Checklist
server.shutdown=graceful+ spring.lifecycle.timeout-per-shutdown-phase=30s — avoid deploy interrupting in-flight requests. management.endpoints.web.exposure.include only health, metrics, prometheus. Never include=* — especially env, heapdump, threaddump leak sensitive data. spring.profiles.active injected externally — not hardcoded in JAR; same artifact deploys to multiple envs via env vars or args. spring.main.allow-bean-definition-overriding=false (3.x default) — good thing, keep it to expose bean conflicts early instead of silent override.
Logging & structured output: 3.4 supports logging.structured.format.console=ecs for direct structured logs, easy collection to ELK/Loki.
6.4 Error Quick Reference
Port 8080 already in use : Port conflict. Change server.port or server.port=0 random (common in tests).
Consider defining a bean of type 'xxx' : Usually not "forgot @Bean" but condition unsatisfied (missing dep, missing config, package not scanned). Check --debug Negative matches first.
Circular view path / BeanCurrentlyInCreationException : Former: Controller returns view name same as request path loop; latter: constructor injection circular dependency. 3.x defaults to disallow circular deps — best fix: refactor dependencies, not allow-circular-references=true.
NoClassDefFoundError: javax/servlet/... : Classic 2.x dep mixed into 3.x project. Use mvn dependency:tree to find old libs still pulling javax and upgrade.
7. One-Page Cheat Sheet
[Positioning] Assembler + runtime, doesn't replace Spring
[Three-in-one] @SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan
[Auto-config] read imports → dedupe exclude
→ batch filter → condition eval
→ sort register
[Conditions] OnClass / OnMissingBean
/ OnProperty / OnWebApplication
[Yield] OnMissingBean: you register first I back off
[Startup 9 steps] construct → env → context
→ prepare → refresh → started
→ runners → ready
[Refresh] 05 auto-config / 09 start container
11 create beans / 12 publish events
[Tomcat] onRefresh → createWebServer
→ factory.getWebServer → start
[Config] cmdline > env vars > external files
> jar internal > defaults
[Profile] application.yml base
application-{p}.yml overrides
[Packaging] JarLauncher + nested jar loader
[Debug] --debug view Positive/NegativeIf only one sentence remembered : Spring Boot has no magic — it merely "conditionally" writes a batch of @Bean for you before container refresh.
From one-line main to port listening, from auto-config to fat JAR loading, the chain is closed. Next highest-value action: add --debug to your own project, run once, match Positive matches line-by-line to this article's mechanisms . Understand the wiring, then dare to change config.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
