Grokking Spring Boot
Vote

0% completed

​

Inside a Spring Boot Project

The Build File

The Parent: Versions Chosen for You

Starters: One Dependency, Many Libraries

The Main Class and the Package Layout

The Settings File

The Test Folder

The Maven Wrapper

Key Takeaways

Practice Questions

These are the files that the Spring Initializr generates for the booking service, with web support selected:

booking/ pom.xml mvnw mvnw.cmd .mvn/wrapper/maven-wrapper.properties src/main/java/com/example/booking/BookingApplication.java src/main/resources/application.properties src/test/java/com/example/booking/BookingApplicationTests.java .gitignore HELP.md

Only one file holds Java code that runs in production, and it is 13 lines long. The rest describe how to build the project, how to configure it, and how to test it. Each file has one job, and knowing those jobs tells you which file a later change belongs in. The sections below examine the files one at a time.

The Build File

The file pom.xml tells Maven, the build tool, what the project is called, which libraries it needs, and how to package it. Maven reads this file before it compiles anything. The generated file is longer, but these parts do the work:

<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>4.1.2</version> </parent> <groupId>com.example</groupId> <artifactId>booking</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <java.version>21</java.version> </properties> <dependencies> <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> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>

The three lines groupId, artifactId, and version name the project, and Maven uses them to name the packaged file. The property java.version sets the Java version for compiling. The dependencies section lists two starters, and the plugin at the end builds the runnable jar that the next lesson opens.

Notice that neither dependency has a version tag. The parent supplies every version.

The Parent: Versions Chosen for You

The parent, spring-boot-starter-parent, is a shared build file that the project inherits settings from, and its most important setting is a list of library versions. The Spring Boot documentation names what it provides: Java 17 as the default compiler level, UTF-8 source encoding, and dependency management. Dependency management is a list of tested versions, so the project can omit version tags for those libraries.

For the booking service, choosing parent version 4.1.2 fixed every version below it. When we built the project, Maven selected Spring MVC 7.0.10, Tomcat 11.0.27, Jackson 3.1.7 (the library that converts Java objects to JSON), and Logback 1.5.38 (a logging library). Nobody typed those numbers.

This has one benefit and one cost:

  • The benefit: the Spring team tests these versions together, so the project does not combine a web framework and a server that are incompatible.
  • The cost: upgrading Spring Boot upgrades all of them at once. An upgrade is one line in the build file, but it must be tested like many changes.

Starters: One Dependency, Many Libraries

A starter is a dependency that exists only to bring in a set of other libraries that work together. It contains almost no code of its own. Its value is the list of libraries it declares.

Maven can print what a dependency brings in. For spring-boot-starter-webmvc, the output (shortened here) groups into five kinds of library:

spring-boot-starter-webmvc:4.1.2 +- spring-boot-starter:4.1.2 | +- spring-boot-starter-logging:4.1.2 (Logback) | \- spring-boot-autoconfigure:4.1.2 +- spring-boot-starter-jackson:4.1.2 (Jackson, for JSON) +- spring-boot-starter-tomcat:4.1.2 (embedded Tomcat 11.0.27) \- spring-boot-webmvc:4.1.2 \- spring-webmvc:7.0.10 (Spring MVC)

When we packaged the project, it contained 34 library jars, all from this one starter. One of them, spring-boot-autoconfigure, holds the auto-configuration rules described in What Spring Boot Is.

One starter, versions from the parent, and the libraries it brings into the application.
One starter, versions from the parent, and the libraries it brings into the application.

Notice the order in the picture. The parent decides the versions first, and the starter then pulls in libraries at those versions. The second starter, spring-boot-starter-webmvc-test, works the same way for testing libraries. Its scope is test, so its libraries never reach the packaged application.

The Main Class and the Package Layout

The main class is the class whose main method starts the application, and its package is the root of component scanning. In this project it is BookingApplication, in the package com.example.booking. As shown earlier, Spring scans only that package and the packages below it.

The usual layout therefore keeps the main class at the top and groups the rest of the code by feature:

com.example.booking BookingApplication com.example.booking.events events and seats com.example.booking.bookings creating and canceling bookings com.example.booking.payments the payment client

Every feature package sits below the root, so scanning finds every class. Grouping by feature also keeps related classes together. A change to payments then touches one package, instead of separate packages for controllers, services, and repositories.

The Settings File

The file application.properties holds settings as key and value pairs, and Spring Boot reads it at startup. The generated file has one line:

spring.application.name=booking

This setting names the application. You can see it in every line of the startup log, which shows [booking] after the process number. Settings such as the server port and, later, the database address also go in this file. A later lesson explains how values from the environment and the command line override it.

The Test Folder

Code under src/test is compiled and run by the build, but it is never packaged into the application. The Initializr generates one test:

@SpringBootTest class BookingApplicationTests { @Test void contextLoads() { } }

The test body is empty, yet the test is useful. The annotation @SpringBootTest starts the whole application, with every bean, before the test runs. If any bean cannot be created, the test fails. When we ran the build, the result was "Tests run: 1, Failures: 0", which proves the application can start.

The Maven Wrapper

The files mvnw, mvnw.cmd, and the .mvn folder form the Maven wrapper, a small script that downloads the correct Maven version and then runs it. Nobody on the team needs to install Maven. Each developer, and the build server, runs ./mvnw on Linux and macOS, or mvnw.cmd on Windows.

On its first use, the wrapper in this project downloaded Maven 3.10.0 and stored it in the user's home folder. Later runs use that copy. Commit the wrapper files to version control, so every machine builds with the same Maven version.

The five main files of a generated project, what each one does, and which ones reach the packaged application.
The five main files of a generated project, what each one does, and which ones reach the packaged application.

Notice the last column of the picture. The build file, the wrapper, and the test are used only by the build, while the compiled main class and the settings file are packaged inside the application.

Key Takeaways

  • The file pom.xml names the project, lists its starters, and adds the plugin that builds the runnable jar.
  • The parent fixes a tested version for every library, so dependencies need no version tags.
  • A starter is a list of libraries: spring-boot-starter-webmvc brings Spring MVC, Tomcat, Jackson, and logging.
  • The main class sits in the root package, and feature packages go below it so scanning finds them.
  • The test folder and the Maven wrapper support the build but are not packaged into the application.

The project builds and its one test passes, but it has not been run yet outside a test. Running and Packaging an Application starts it in three ways and opens the jar that the build produces.

Practice Questions

1. A developer adds a library that the parent manages and also writes its version tag by hand, choosing an older version. What risk does this create?

<details><summary>Show answer</summary>

The project now mixes a version the Spring team did not test with the versions that the parent chose. The hand-written version overrides the managed one. The library may then be incompatible with Spring or with another library, and the problem often appears only at runtime, not at compile time. A version tag on a managed library needs a specific reason.

</details>

2. The team moves BookingApplication into a new package, com.example.booking.app, and leaves the other classes where they are. What breaks?

<details><summary>Show answer</summary>

Component scanning now starts at com.example.booking.app, so it no longer finds the classes in com.example.booking.events and the other feature packages. Those classes are not below the new root, so they never become beans, and their endpoints return 404 Not Found. The main class belongs in the root package.

</details>

3. The test contextLoads has an empty body. A colleague wants to delete it because "it tests nothing". What does it actually check?

<details><summary>Show answer</summary>

It checks that the whole application can start. The annotation @SpringBootTest builds every bean before the test runs, so a missing dependency, a broken configuration, or a bad setting fails the test. It is the cheapest test of the wiring, and it should stay.

</details>

4. A library is needed only by tests. Where does it go in pom.xml, and how does that affect the application?

<details><summary>Show answer</summary>

It goes in the dependencies section with a scope of test. Maven then puts it on the classpath only while compiling and running tests. The packaged application does not contain it, so it adds no size and no risk in production.

</details>

Reading Progress

0%


Vote for new content

On This Page

The Build File

The Parent: Versions Chosen for You

Starters: One Dependency, Many Libraries

The Main Class and the Package Layout

The Settings File

The Test Folder

The Maven Wrapper

Key Takeaways

Practice Questions