Keentune
Spring Boot, oriented
12 chapters
·
about 16 min read
·
free
Most of a Spring Boot application is code you did not write. A container builds your objects and decides what each receives; a jar on the classpath adds beans you never declared; configuration arrives from files, environment and command line at once; and your class is usually wrapped in a proxy before anyone calls it. Nearly every baffling failure is a disagreement between what you wrote and what the framework did around it — a value with no visible source, an annotation that silently does not fire, a bean missing or present twice. This guide walks the framework in that order. Claims come from the Spring Boot 4.1 and Spring Framework 7.0 reference documentation; behaviour moves between major versions, so check yours.
Each chapter opens with the short version. Tap one to read the detail.
Your main method hands over control
~2 min
SpringApplication.run builds a container that finds your classes, constructs them and connects them. It scans downward from the package of the annotated class, so a component sitting in a sibling package is not a wiring bug — it is invisible.
What the container hands you, and what it refuses to
~2 min
Dependencies are matched by type first, with the bean name only as a fallback. So adding a second implementation of an interface is a breaking change: the container that wired one bean happily now fails, because it cannot choose between two.
How long a bean lives
~2 min
Singleton is the default and means one instance per container, not one per process. The trap is that scope is resolved at the injection point: a prototype injected into a singleton is looked up once, so you hold that "new every time" object forever.
The classpath is an input
~2 min
Auto-configuration inspects the jars you depend on and adds beans accordingly, so a dependency change alters runtime behaviour with no code change. It is non-invasive by design: define your own bean of the same kind and the default steps aside.
Where a value actually came from
~2 min
Configuration is assembled from many sources at once, and later sources override earlier ones. Your packaged application.properties sits near the bottom, with environment variables and command-line arguments above it — so a value that disagrees with the file is usually not a bug.
One servlet in front, then your method
~2 min
Every request enters through a single front controller that consults its handler mappings to choose a method. Validation is part of that dispatch: @Valid normally rejects a bad request for you — unless you add an Errors parameter directly after it, which quietly makes rejection your job.
The proxy is the annotation
~2 min
@Transactional and its relatives are not compiled into your method; they are applied by a proxy wrapped around your bean. Only calls arriving through that proxy are intercepted, so one method of a class calling another directly runs with no transaction at all.
A repository you never implemented
~2 min
Boot supplies a DataSource, entity scanning, and repository interfaces whose implementations are generated from their method names. It also holds the persistence context open for the whole web request by default, which is why lazy loading works in a controller and fails everywhere else.
A filter chain in front of everything
~2 min
Adding the security starter secures the whole application immediately — every endpoint, including /error and actuator — with one in-memory user whose password is printed in the startup log. Writing your own filter chain replaces the rules, but not that user.
The context is the expensive part
~2 min
@SpringBootTest finds your configuration by searching upward from the test's own package and boots a whole application context — but contexts are cached and shared by every test whose configuration matches. A slow suite is usually not slow tests; it is many different contexts.
Work that leaves the request thread
~2 min
Calling another service, scheduling a job and going reactive are one problem wearing three hats: the work is on a thread whose budget you did not set. Timeouts have no documented defaults, the scheduler runs a single thread, and one blocking call on an event loop stalls every request in flight.
What the running process will tell you
~2 min
Actuator endpoints are enabled but almost none are exposed: over HTTP you get health, and its details are hidden. Logging has the same shape — console only, no file — so both are decisions to make before production rather than defaults to inherit.
See the full Spring Boot curriculum
Written by Keentune. We are not affiliated with or endorsed by the organizations whose documentation informs this guide, and any linked sources belong to their respective owners.
All exam, test, and product names and trademarks are the property of their respective owners and are used here for identification and reference only. Keentune is independent study practice — not affiliated with, authorized, or endorsed by any of these organizations.
© 2026 SportaApp LLC