What Spring Boot Is

Spring Boot is an opinionated layer over the Spring Framework that configures it for you, runs it on an embedded server and ships it as one jar.

Syntax@SpringBootApplication public class App { public static void main(String[] args) { SpringApplication.run(App.class, args); } }

The Spring Framework is a container that creates your objects, wires them together and hands them web, data and transaction support. It is powerful and very configurable, which used to mean a lot of configuration: a servlet container to install, a DispatcherServlet to register, a connection pool, a JSON converter and a transaction manager to declare by hand.

Spring Boot removes that work. It is not a different framework: every controller, repository and @Transactional method you write is plain Spring. Boot adds four things on top.

  • Starters: one dependency such as spring-boot-starter-webmvc brings a tested set of libraries with versions that work together.
  • Auto-configuration: Boot looks at what is on the classpath and which beans you have declared, then creates sensible defaults. Add the JDBC or JPA starter, the PostgreSQL driver and a URL, and you get a pooled DataSource.
  • An embedded server: Tomcat runs inside your process. There is no server to install; the application is started with java -jar.
  • Externalised configuration and production features: properties, profiles and environment variables, plus Actuator for health checks and metrics.

Opinions you can override

Every default backs off when you supply your own. Declare a DataSource bean and Boot stops creating one. Set server.port and Tomcat listens elsewhere. You start with working defaults and replace only the parts that matter to you.

When it fits

Boot is the standard way to build Spring services: REST APIs, message consumers, scheduled jobs and back-office applications. It suits teams that deploy one service per process, in containers or on a plain VM. It is a weaker fit for a tiny command-line tool where start-up time and jar size dominate, although AOT processing and native images narrow that gap.

Mistakes to avoid

The common one is treating auto-configuration as magic. When a bean appears that you did not declare, or one you expected is missing, the conditions report (start with --debug) tells you exactly which configuration ran and why. The second is adding starters "just in case": each one switches on auto-configuration, can add connections, health checks and endpoints you never asked for, and widens your attack surface. Add a starter when you write the code that needs it.

In production, the defaults are a starting point, not a finished setup. Pool sizes, timeouts, logging format and which Actuator endpoints are exposed all need a deliberate choice, and later stages of this course cover each one.

Example

Example · java

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
public class GreetingApplication {

    public static void main(String[] args) {
        // Starts the container, applies auto-configuration and boots embedded Tomcat on port 8080.
        SpringApplication.run(GreetingApplication.class, args);
    }
}

record Greeting(String message) {
}

@RestController
class GreetingController {

    @GetMapping("/greetings/{name}")
    Greeting greet(@PathVariable String name) {
        // The record is written as JSON by the auto-configured Jackson converter.
        return new Greeting("Hello, " + name);
    }
}

When to use it

  • Start a new REST service that runs with java -jar and needs no application server installed.
  • Replace hand-written XML or Java configuration for MVC, JSON and the connection pool with defaults you override selectively.
  • Give every service in a team the same health checks, metrics and configuration conventions.

More examples

The configuration Boot replaces

Without Boot you would register a servlet container, a DispatcherServlet and a JSON message converter in code. With Boot the only configuration is the values you want to differ from the defaults. Turning on debug logging for org.springframework.web is a quick way to watch each request being mapped to a handler method.

Example · properties
# Nothing is required: these lines only change defaults Boot already chose.
spring.application.name=greeting-service
server.port=8081
logging.level.org.springframework.web=debug

The dependencies behind it

The parent POM imports Boot's dependency management, so no starter needs a version. That is the main reason upgrades are manageable: you change one version number and every library moves to a combination the Spring team has tested together.

Example · xml
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>4.1.1</version>
    <relativePath/>
</parent>

<dependencies>
    <!-- Spring MVC, Jackson and embedded Tomcat, all at matching versions -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webmvc-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Proving it works with a slice test

@WebMvcTest starts only the web layer, with the same JSON setup the real application uses, and no server socket. In Spring Boot 4 the annotation lives in org.springframework.boot.webmvc.test.autoconfigure and comes from spring-boot-starter-webmvc-test. The test runs in well under a second, which is what makes testing controllers routine rather than a chore.

Example · java
import static org.assertj.core.api.Assertions.assertThat;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.webmvc.test.autoconfigure.WebMvcTest;
import org.springframework.test.web.servlet.assertj.MockMvcTester;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

record Greeting(String message) {
}

@RestController
class GreetingController {

    @GetMapping("/greetings/{name}")
    Greeting greet(@PathVariable String name) {
        return new Greeting("Hello, " + name);
    }
}

@WebMvcTest(GreetingController.class)
class GreetingControllerTest {

    @Autowired
    MockMvcTester mvc;

    @Test
    void greetsByName() {
        assertThat(mvc.get().uri("/greetings/{name}", "Ada"))
                .hasStatusOk()
                .bodyJson()
                .extractingPath("$.message")
                .isEqualTo("Hello, Ada");
    }
}

Discussion

  • Be the first to comment on this lesson.