All levelsLearning path

Mastering Spring Boot

The full path from core Java to a Spring Boot 4 service you would be happy to run in production.

The whole path at a glance. Jump to any stage. Scroll sideways to see it all.

Spring Boot is not large because it is complicated. It is large because it has an answer for almost everything a backend service needs, and nobody tells you which of those answers you need first. The usual result is an engineer who can scaffold a controller but cannot say what the container did with it.

This path is ordered the way the understanding actually has to arrive. Java first, because Spring is a library and not a language. Then the container, because every Spring feature you will ever meet is a bean somewhere. Then Boot itself, which is mostly the container plus opinions. Everything after that is a capability you bolt on when the application needs it.

Stages run top to bottom. Where a stage branches, the nodes in it are genuinely independent — pick the one your current work needs and come back for the others. Nothing here assumes you want microservices; the single-service path is complete on its own, and stops being complete only when one deployable stops being enough.

The path

Take in orderBranches — any order

  1. Stage 1Core Java

    Spring cannot teach you Java, and most "Spring is confusing" turns out to be a gap here. These four areas are independent of each other.

    4 parallel branches

  2. Stage 2The JDK and your build

    A short stage, but skipping it is why dependency problems feel like magic later.

    • JDK, Maven or Gradle

      Spring Boot 4 sets a Java 17 baseline and is built to run on 25 — pick an LTS and know what your build is doing with it.

      • Java 17 baseline, Java 21 or 25 in practice
      • Maven and Gradle: the parts you actually edit
      • Version management through the Spring Boot BOM
      • Executable jars and what is inside one
      • Generating a project with Spring Initializr
  3. Stage 3Spring core: the container

    The single highest-leverage stage on this path. Everything later is this plus configuration.

    • Beans and dependency injection

      A bean is an object the container built and now owns. Almost every Spring question reduces to a question about that ownership.

      • The ApplicationContext and bean definitions
      • Constructor injection, and why not field injection
      • Singleton scope and what it means for your state
      • Component scanning versus explicit @Bean methods
      • Qualifiers and resolving ambiguity
    • Proxies and AOP

      The one mechanism that explains why @Transactional, @Cacheable and @Async all stop working when you call them from the same class.

      • What a proxy is and when Spring makes one
      • Self-invocation, and why it bypasses the proxy
      • Aspects, pointcuts, advice
      • Reading a Spring stack trace through the proxy layers
  4. Stage 4Spring Boot itself

    Boot is the container plus a set of defaults that back off the moment you define your own bean.

    • Starters and auto-configuration

      Auto-configuration is conditional beans, nothing more. Once you can read a condition you can predict what Boot will do.

      • Starters and the dependencies they pull in
      • @ConditionalOnClass, @ConditionalOnMissingBean
      • Overriding a default by declaring your own bean
      • The auto-configuration report, for when it did not
    • Configuration and profiles

      The same artefact has to run on a laptop and in production. Everything that differs belongs here, not in the code.

      • application.yaml and the property source order
      • Type-safe @ConfigurationProperties
      • Profiles for environments, not for features
      • Secrets through the environment, never the repo
  5. Stage 5Web and REST

    Four independent concerns. Controllers first; the rest in whatever order your API needs them.

    4 parallel branches

  6. Stage 6Data and persistence

    Start with mapping and transactions. Performance and migrations become urgent the moment real data arrives.

    4 parallel branches

    • Spring Data JPA

      JPA is a cache with a database behind it. Knowing which state an entity is in explains most of its surprises.

      • Entities, relationships, fetch types
      • The persistence context and entity lifecycle
      • Repositories, derived queries, @Query
      • LazyInitializationException and what it is telling you
    • Transactions

      Where a transaction starts and ends is a design decision. Leaving it to @Transactional on a service method is still a decision.

      • Declarative @Transactional and its proxy
      • Propagation and when a new transaction is created
      • Isolation levels and the anomalies they prevent
      • readOnly, and rollback rules you did not intend
    • Query performance

      Almost every slow Spring Boot endpoint is the same bug: one query turned into hundreds.

      • The N+1 problem, and fetch joins or entity graphs
      • Projections instead of whole entities
      • Batch inserts and updates
      • Caching, and what is safe to cache
    • Schema migrations

      Hibernate generating your schema is a development convenience that has no production equivalent.

      • Flyway or Liquibase as the source of truth
      • Versioned, forward-only changes
      • Backwards-compatible migrations for zero-downtime deploys
      • Turning ddl-auto off and keeping it off
  7. Stage 7Security

    Learn the filter chain before anything else here; every later surprise is a filter ordering question.

    • The filter chain

      Spring Security is a chain of servlet filters. Configuration you cannot explain in those terms will not behave as you expect.

      • SecurityFilterChain and request matchers
      • Authentication versus authorisation
      • The SecurityContext and where it lives
      • CSRF, CORS and session policy
    • Authentication and access control

      Issuing and checking identity, and expressing who may do what in a way you can test.

      • Stateless JWT-bearing resource servers
      • OAuth2 and OIDC login
      • Method-level @PreAuthorize rules
      • Password storage, if you really must own it
  8. Stage 8Testing

    Not a late stage in practice — fold it in from the first endpoint. It sits here because it needs the vocabulary above.

    2 parallel branches

    • Test slices

      Booting the whole context for every test is why suites get slow. Boot gives you narrower contexts on purpose.

      • Plain unit tests, with no Spring at all
      • @WebMvcTest, @DataJpaTest, @JsonTest
      • @SpringBootTest and when it is warranted
      • Mocking a bean versus stubbing a collaborator
    • Integration testing

      An in-memory database tests an in-memory database. Test against the engine you deploy on.

      • Testcontainers for the real database and broker
      • Boot 4 service connections, wired from the container
      • WireMock for the services you do not own
      • Keeping tests independent of execution order
  9. Stage 9Observability and operations

    The difference between a service you own and one you merely wrote.

    • Actuator and metrics

      Health, metrics and configuration introspection, exposed deliberately rather than by default.

      • Actuator endpoints, and locking them down
      • Liveness and readiness probes that mean something
      • Micrometer metrics and a meaningful custom one
      • Structured logging you can actually query
    • Tracing

      Once a request crosses a process boundary, logs alone stop being able to tell you where the time went.

      • Micrometer Observation and spans
      • Trace and span ids propagated across calls
      • OpenTelemetry export
      • Correlating a trace back to a log line
  10. Stage 10Async work and messaging

    Two independent answers to "this should not happen inside the request".

    2 parallel branches

    • Async and scheduled work

      In-process background work: cheap, and lost the moment the process dies.

      • @Async and the executor behind it
      • CompletableFuture composition
      • @Scheduled jobs, and running them on one instance only
      • Virtual threads for blocking workloads
    • Messaging

      Durable work that outlives a restart, and the decoupling that comes with it.

      • Kafka or RabbitMQ, and which problem each fits
      • Producers, consumers, acknowledgement
      • At-least-once delivery and idempotent consumers
      • Dead letter topics and retry policy
  11. Stage 11Microservices

    Only worth reaching for when one deployable has become the constraint. The whole path above still applies to each service.

    • Service boundaries

      Splitting along the wrong seam gives you a distributed system with none of the independence that justified it.

      • Decomposing by business capability
      • One database per service, and the consequences
      • Synchronous calls versus events
      • Eventual consistency and the saga pattern
    • Resilience

      In one process a failed call throws. Across a network it hangs, and takes your thread pool with it.

      • Retries with backoff, without amplifying an outage
      • Circuit breakers and deliberate thresholds
      • Bulkheads, rate limiters, concurrency limits
      • Spring Framework 7 @Retryable and @ConcurrencyLimit
      • Fallbacks that degrade instead of returning 500
    • Gateway and platform concerns

      The things that stop being free the moment there is more than one service.

      • An API gateway for routing and edge auth
      • Service discovery, or stable DNS
      • Centralised configuration
      • Distributed tracing across the call chain
  12. Stage 12Shipping it

    The last stage, and the one that decides whether any of the above reaches a user.

    • Containers and startup

      How the jar becomes something a platform can run, and what that costs at boot.

      • Layered images and Cloud Native Buildpacks
      • GraalVM native images, and the trade you are making
      • Right-sizing the JVM in a container
      • Graceful shutdown and in-flight requests
    • Delivery

      A deploy you are nervous about is a deploy you will do rarely, which makes it riskier still.

      • CI that builds, tests and publishes one artefact
      • Promoting the same image through environments
      • Database migrations in the deploy pipeline
      • Feature flags instead of long-lived branches