If you already write Java, you have probably heard of Spring as "the framework everyone uses in the enterprise world". And you have probably also heard the historic complaint that came with it: that configuring it was a long, repetitive chore full of XML files. Spring Boot was born precisely to remove that pain. This lesson explains the specific problem Spring Boot solves, how it solves it through four very recognisable mechanisms, and where it fits inside the Spring ecosystem. By the end you will also have met CicloUrbana, the real application you will build step by step throughout the course and that will give practical meaning to every concept.

Contents

  1. Spring Framework: the starting point
  2. "Configuration hell": a real side-by-side example
  3. The four pillars of Spring Boot
  4. Spring Boot within the Spring ecosystem
  5. What kind of applications are built with Spring Boot
  6. The course project: CicloUrbana
  7. Spring Boot 3.x versions and Java requirements
  8. Common Mistakes and Tips
  9. Exercises

  1. Spring Framework: the starting point

Before you can understand Spring Boot you need to understand what Spring Framework is, because Spring Boot does not replace it: it wraps it.

Spring Framework appeared in 2003 with one central idea: the inversion of control container (IoC, Inversion of Control). Instead of every class creating the objects it needs with new, the framework creates those objects —called beans— and hands them to whoever asks for them. That is what we call dependency injection.

The payoff is immediate:

  • Classes depend on interfaces, not on concrete implementations.
  • The code is easy to test, because in a test you can inject a fake implementation.
  • The configuration of "what is wired to what" lives in a single place instead of being scattered across the code.

On top of that core, Spring kept adding modules: data access, transactions, MVC for the web, security, messaging... All of it excellent. The problem was never the power, it was the cost of getting started.

  1. "Configuration hell": a real side-by-side example

Until roughly 2014, getting a Spring web application up and running with one HTTP endpoint and a database connection required all of this groundwork:

  1. Create a Maven project and hand-pick the version of every library (Spring Core, Spring MVC, Spring JDBC, Jackson, a connection pool, the JDBC driver...), praying they were compatible with each other.
  2. Write a web.xml to register Spring's servlet.
  3. Write one or more XML context files declaring the beans.
  4. Package a WAR file and deploy it to a separately installed application server (Tomcat, JBoss, WebLogic).

Here is how something as basic as a data source and a transaction manager was declared in the classic style:

<!-- applicationContext.xml — classic Spring configuration (old style) -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="...">

    <!-- 1. The connection pool has to be declared by hand -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource"
          destroy-method="close">
        <property name="driverClassName" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://localhost:5432/ciclourbana"/>
        <property name="username" value="ciclo"/>
        <property name="password" value="secret"/>
        <property name="maxTotal" value="20"/>
    </bean>

    <!-- 2. The transaction manager has to be declared and wired to the dataSource -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!-- 3. @Transactional support has to be switched on explicitly -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

    <!-- 4. And Spring has to be told where to look for your classes -->
    <context:component-scan base-package="com.ciclourbana"/>
</beans>

Plus a web.xml to boot all of that inside the server:

<!-- web.xml — required so the application server loads Spring -->
<web-app>
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

That is roughly 40 lines of configuration that deliver no business functionality whatsoever: there is not a single bike station or rental in sight. It is pure scaffolding. And it has to be repeated, with variations, in every new project.

The same thing with Spring Boot

With Spring Boot, that entire block shrinks to one properties file and one startup class:

# src/main/resources/application.properties
spring.datasource.url=jdbc:postgresql://localhost:5432/ciclourbana
spring.datasource.username=ciclo
spring.datasource.password=secret
package com.ciclourbana;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class CicloUrbanaApplication {

    public static void main(String[] args) {
        SpringApplication.run(CicloUrbanaApplication.class, args);
    }
}

An explanation of what just happened:

  • Spring Boot detects that there is a PostgreSQL driver on the classpath and that a spring.datasource.url property exists. With that it creates the DataSource for you, using HikariCP as the connection pool.
  • It also detects that there is a DataSource, creates the transaction manager and switches on @Transactional support.
  • The component-scan switches itself on, rooted at the package that holds the class annotated with @SpringBootApplication (com.ciclourbana).
  • No web.xml is needed because there is no external server: the server lives inside the application.

The comparison in short:

Aspect Classic Spring (pre-Boot) Spring Boot
Library versions Hand-picked and reconciled Managed by the parent / BOM
Infrastructure configuration Lengthy XML or @Configuration Autoconfiguration + properties
Web server External, installed separately Embedded in the JAR
Deployment artefact WAR deployed into a container Executable JAR (java -jar)
Time to the first endpoint Hours Minutes
Metrics, health, logs Added by hand Actuator, production-ready

Key idea: Spring Boot is not a new framework competing with Spring. It is a layer of opinion and automation on top of Spring Framework. Everything you know about Spring still holds; you simply stop writing the boring part.

  1. The four pillars of Spring Boot

Almost everything Spring Boot does comes down to four mechanisms. It pays to be clear about them from day one, because you will meet them again and again.

3.1 Autoconfiguration

Spring Boot looks at what is on the classpath and at what you have configured, and from that it automatically registers the beans you would normally need. If it finds the Spring MVC library, it configures a DispatcherServlet. If it finds a JDBC driver and a URL, it configures a DataSource.

The golden rule is that autoconfiguration is conditional and steps aside: if you define your own bean, Spring Boot backs off and uses yours. It never blocks you. The internal mechanism (the @Conditional... annotations) is studied in detail in module 2, lesson 02-06.

3.2 Starters

A starter is a Maven dependency that contains no code, but rather a curated list of dependencies that work well together. Instead of adding eight libraries with their versions, you add one:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

That single line pulls in Spring MVC, Jackson (for JSON), validation, logging and an embedded Tomcat, all at mutually compatible versions. Notice there is no <version> tag: the version is decided by the Spring Boot parent. Starters are covered in lesson 01-04 and their inner workings in 02-06.

3.3 Embedded web server

A Spring Boot web application contains its own server. Running java -jar ciclourbana.jar starts a Tomcat (or Jetty, or Undertow) inside the very same Java process.

The consequences are far-reaching:

  • The artefact is self-contained: a single JAR file with everything inside.
  • The application runs the same way on your laptop as it does in production.
  • It fits naturally with Docker containers and cloud platforms, where the model is "one process, one port".
  • The whole class of "it works on my machine, but the server's Tomcat is a different version" errors simply disappears.

3.4 Production-ready features

With a single dependency (Actuator), Spring Boot ships everything an application needs to live in production:

  • Health endpoints (/actuator/health) that a load balancer or Kubernetes can query.
  • Metrics (memory, requests per second, latencies) exportable to Prometheus.
  • Application information, a dump of the effective configuration, and log level changes at runtime.

All of this is covered in modules 7 and 9. I mention it here only because it exists, because it is one of the four pillars and it explains why Spring Boot is the de facto enterprise standard.

  1. Spring Boot within the Spring ecosystem

"Spring" is a family of projects. This table places each piece and tells you in which module of the course it will show up:

Project What it brings When will you use it in CicloUrbana?
Spring Framework The core: IoC container, dependency injection, AOP, transactions, Spring MVC Modules 2 and 3
Spring Boot Autoconfiguration, starters, embedded server, Actuator The whole course
Spring Data JPA Automatic repositories over relational databases Module 4
Spring Security Authentication, authorisation, API protection, JWT Module 5
Spring Test Testing utilities integrated with JUnit and Mockito Module 6
Spring Cloud Distributed configuration, service discovery, fault tolerance Module 7 (introduction)
Spring Batch / Integration Batch processing and systems integration Outside the scope of the course

Think of Spring Boot as the integrator: it does not reimplement Spring Data or Spring Security, it autoconfigures them so that they work the moment you add their starter.

  1. What kind of applications are built with Spring Boot

Spring Boot is not limited to REST APIs, even if that is its most common use:

  • REST APIs and backends for web or mobile applications. This is the majority case, and the one this course follows.
  • Microservices. Each service is a self-contained JAR with its own port and its own database.
  • Traditional web applications with server-side views (Thymeleaf, FreeMarker).
  • Command-line applications and batch processes, with no web server, using CommandLineRunner (lesson 01-05).
  • Messaging consumers (Kafka, RabbitMQ) or scheduled tasks (module 7).
  • GraphQL APIs or reactive services with Spring WebFlux, for extremely high concurrency loads.

  1. The course project: CicloUrbana

Throughout the course you will build CicloUrbana, the platform that manages the municipal electric bike network of Ribalta, a fictional medium-sized city.

The business context

Ribalta's city council has installed docking stations across the city —"Main Square", "North Station", "River Park" and "University", among others—. Each station has a limited number of docks and a set of geographic coordinates. They hold electric bikes identified by plates such as RB-0142, each with a battery level and a status.

A registered user unlocks a bike at one station, rides it and returns it at another station. That journey is a rental, charged according to a fare. If something goes wrong —a broken brake, a battery that will not charge—, an incident is opened.

The actors

Actor What they do in the system
Citizen user Browses stations and available bikes, starts and finishes rentals, views their history
Maintenance operator Receives incidents, changes bike statuses, rebalances stations
Council manager Reviews usage statistics, manages fares, registers new stations
External system The mobile app and the station information panels consume the API

The API you will end up with

By the end of the course, CicloUrbana will expose a REST API versioned under /api/v1. A preview of its final shape:

Method and path Purpose
GET /api/v1/stations List stations, with filters and pagination
GET /api/v1/stations/{id} Details of one station
POST /api/v1/stations Register a station (manager only)
GET /api/v1/stations/{id}/bikes Bikes available at a station
POST /api/v1/rentals Start a rental
POST /api/v1/rentals/{id}/finish Return the bike and calculate the amount
POST /api/v1/incidents Report a fault
POST /api/v1/auth/login Obtain a JWT token

The target architecture

flowchart TD
    subgraph Clients
        A["Mobile app"]
        B["Station panel"]
        C["Council back office"]
    end

    A --> API
    B --> API
    C --> API

    subgraph "CicloUrbana (Spring Boot)"
        API["Web layer<br/>REST controllers /api/v1"]
        SEC["Spring Security<br/>JWT + roles"]
        SRV["Service layer<br/>Business rules"]
        REP["Spring Data JPA<br/>Repositories"]
        ACT["Actuator<br/>health and metrics"]

        API --> SEC
        SEC --> SRV
        SRV --> REP
    end

    REP --> DB[("PostgreSQL")]
    ACT --> MON["Prometheus / Grafana"]

Do not worry if some of the boxes are unfamiliar: each one corresponds to a module of the course. In module 1 you will only build the web layer with fixed in-memory data; the rest will arrive in due course.

Project conventions

These decisions will stay unchanged for the whole course:

Item Value
groupId com.ciclourbana
artifactId ciclourbana
Base package com.ciclourbana
Java 21 (LTS)
Spring Boot 3.x
Build Maven, with the mvnw wrapper
API prefix /api/v1
Code language Identifiers and comments in English

  1. Spring Boot 3.x versions and Java requirements

Spring Boot 3 was a significant break with the 2.x branch:

  • It requires Java 17 as a minimum. This course uses Java 21, the recommended LTS release, which brings records, pattern matching and virtual threads.
  • Migration from javax.* to jakarta.*. The persistence and validation annotations moved from javax.persistence to jakarta.persistence. If you copy old code from the internet and see javax, it is out of date.
  • It builds on Spring Framework 6, with native support for observability (Micrometer) and for native compilation with GraalVM.
Branch Minimum Java Namespace Status
Spring Boot 2.7 Java 8 javax.* End of free support
Spring Boot 3.0–3.2 Java 17 jakarta.* Older branches of the 3 line
Spring Boot 3.3/3.4/3.5 Java 17 (21 recommended) jakarta.* Branches used in this course

One practical detail: Spring Boot releases minor versions frequently. When you generate the project in lesson 01-03, Spring Initializr will offer you the latest stable release of the 3.x branch. Accept whatever it proposes; everything you learn here is valid on any 3.x.

Common Mistakes and Tips

  • Believing that Spring Boot replaces Spring Framework. It does not. When you debug a problem, remember that underneath there is a perfectly ordinary Spring Framework ApplicationContext. Learning the core (module 2) is what will get you unstuck.
  • Thinking autoconfiguration is uncontrollable magic. It is ordinary Java code, conditional and entirely inspectable. Any bean you define yourself takes precedence over the autoconfigured one.
  • Following Spring Boot 2 tutorials without noticing. Warning signs: javax.persistence imports, WebSecurityConfigurerAdapter, antMatchers(). All of that has disappeared or changed in the 3 branch.
  • Adding dependencies with an explicit version. If the starter manages it, do not pin it yourself: you will break the compatibility the parent guarantees.
  • Tip: get into the habit today of consulting the official documentation at docs.spring.io. It is organised by version and is among the best in the Java ecosystem.

Exercises

Exercise 1

List the four infrastructure tasks a developer had to do by hand in classic Spring and explain, for each one, which pillar of Spring Boot removes it.

Exercise 2

A colleague tells you: "I've added spring-boot-starter-web but I want to use Jetty instead of Tomcat. With Spring Boot you can't choose that any more." Explain why that statement is wrong, drawing on the idea that autoconfiguration "steps aside".

Exercise 3

Design, without writing any code, the REST routes that CicloUrbana's maintenance operator would need in order to do their job. Give the HTTP method and the path under /api/v1, and justify each one briefly.

Solutions

Solution 1

Manual task in classic Spring Pillar that removes it How
Choosing and reconciling library versions Starters A single dependency pulls in a compatible set; the version is pinned by the parent
Declaring infrastructure beans (DataSource, TransactionManager, DispatcherServlet) in XML Autoconfiguration Spring Boot creates them upon detecting libraries and properties
Installing and configuring an external application server and packaging a WAR Embedded server The server travels inside the executable JAR
Adding metrics, health checks and log management by hand Production-ready features Actuator exposes them with a single dependency

Solution 2

The statement is wrong. spring-boot-starter-web includes Tomcat by default, but that is a reversible decision: it is enough to exclude the Tomcat starter and add the Jetty one.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <exclusions>
        <!-- We remove the default server -->
        <exclusion>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<!-- And we add the one we want -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jetty</artifactId>
</dependency>

Once Tomcat is gone from the classpath, the autoconfiguration that activated it no longer applies and Jetty's takes over. This is exactly the principle of "opinionated by default, reversible by decision": Spring Boot chooses for you, but it never ties your hands.

Solution 3

A reasonable proposal for the maintenance operator:

Method and path Rationale
GET /api/v1/incidents?status=OPEN See their pending work queue; filtering by status avoids pulling in unnecessary history
GET /api/v1/incidents/{id} Check the details of a specific fault before travelling out
PATCH /api/v1/bikes/{plate} Change a bike's status (to MAINTENANCE, for example); PATCH because it is a partial modification
POST /api/v1/incidents/{id}/resolve Mark the incident as resolved; modelled as an action because it triggers business logic, it is not a simple field change
GET /api/v1/stations?occupancy=HIGH Spot saturated or empty stations in order to rebalance bikes

Note: POST /api/v1/incidents/{id}/resolve deliberately breaks the strictest REST orthodoxy. It is a very common compromise and we will discuss it in detail in module 3.

Conclusion

Spring Boot is a layer of automation on top of Spring Framework that removes repetitive configuration through four pillars: autoconfiguration, starters, embedded server and production-ready features. It does not replace Spring: it makes it productive from minute one, without taking control away from you, because any automatic decision can be overridden.

You have also met CicloUrbana, Ribalta's electric bike network, which you will build layer by layer: first the web layer with in-memory data, then persistence, security, testing and finally deployment and monitoring.

In the next lesson, Setting Up Your Development Environment, you will get your machine ready: you will install JDK 21, understand why the course uses Maven, choose an IDE and API testing tools, and validate everything against a checklist before writing CicloUrbana's first line.

Spring Boot Course

Module 1: Introduction to Spring Boot

Module 2: Spring Boot Core Concepts

Module 3: Building RESTful Web Services

Module 4: Data Access with Spring Boot

Module 5: Security in Spring Boot

Module 6: Testing in Spring Boot

Module 7: Advanced Spring Boot Features

Module 8: Deploying Spring Boot Applications

Module 9: Performance and Monitoring

Module 10: Best Practices and Tips

© Copyright 2026. All rights reserved