Next step: intro to Spring Boot
What Spring Boot is, dependency injection, creating a project and building your first REST API.
Congratulations: you've reached the final lesson! You can now write solid, modern Java. Most professional Java developers use that skill to build back-end services: the web APIs behind apps and websites. The most popular framework for this is Spring Boot. This lesson explains what it is and walks you through building and testing a small REST API. Everything here was built and run with Spring Boot 4.1 on Java 21.
What Spring and Spring Boot are#
- Spring Framework is a large, mature library for building Java applications. Its core idea is dependency injection (DI): instead of objects creating the things they need with
new, a container creates them and hands them over. - Spring Boot sits on top of Spring and removes most of the setup work:
- Starters: one dependency (e.g.
spring-boot-starter-webmvc) brings in everything for a feature, with compatible versions. - Auto-configuration: Boot looks at what's on the classpath and configures it with sensible defaults. If it sees Spring MVC, you get a web server and JSON support.
- Embedded server: your app is a plain
java -jar app.jarwith Tomcat inside. There's no separate server to install. - Production features: configuration files, profiles, health checks (Actuator), metrics and logging.
- Starters: one dependency (e.g.
Dependency injection in plain Java first
In the second version, Spring is the code that calls new TaskController(theService). Objects managed by Spring are called beans. You mark classes as beans with annotations like @Service, @Repository, @Component and @RestController, and Spring wires them together through their constructors.
Creating a project#
The standard way is the Spring Initializr at start.spring.io:
- Project: Maven, Language: Java, Spring Boot: the latest stable version (4.1.x at the time of writing).
- Group
com.example, Artifacttasks, Java 21. - Add the dependency Spring Web.
- Click Generate, unzip, and open the folder in your IDE. IntelliJ IDEA and VS Code (with the Java and Spring extensions) both have Initializr built in.
Or from a terminal:
You get this layout (the Maven conventions from the build-tools lesson):
The important parts of pom.xml:
The parent manages the versions of hundreds of libraries, so the dependencies have no <version>. (In Spring Boot 3.x the web starter was called spring-boot-starter-web, which you'll see in many tutorials.)
The entry point#
@SpringBootApplication turns on component scanning for this package and its sub-packages, plus auto-configuration. Run it:
Your first endpoint#
Restart the app and call it with a browser or curl:
@RestController: a bean whose methods handle HTTP requests; return values become the response body.@GetMapping("/hello"): handlesGET /hello. There are also@PostMapping,@PutMapping,@DeleteMappingand@PatchMapping.@RequestParam: reads?name=...from the query string.
A small REST API for tasks#
A REST API exposes resources (here: tasks) at URLs and uses HTTP methods for actions:
The data: records
Records are perfect DTOs (data transfer objects). Spring's JSON library (Jackson) converts them to and from JSON automatically:
The business logic: a @Service
For now, we keep tasks in memory using the thread-safe collections from the concurrency module (a web server handles many requests at once):
Notice that this is ordinary Java: streams, Optional, records and ConcurrentHashMap. Everything you learned in this course applies directly.
The web layer: a @RestController
@RequestMapping("/api/tasks")on the class sets a common path prefix.@PathVariablebinds{id}from the URL;@RequestBodyconverts the JSON body into aNewTask.ResponseEntitylets you choose the status code and headers.created(uri)gives 201 with aLocationheader.- There's no
@Autowiredon the constructor: with a single constructor, Spring injects automatically.
Trying it out
(The two -i calls also print headers, which are trimmed here.) Sending {"title": " "} returns 400 Bad Request. For real validation rules, add the Validation starter and annotate the record: record NewTask(@NotBlank String title) with @Valid @RequestBody.
Configuration: application.properties#
You can override any property without rebuilding: java -jar target/tasks-0.0.1-SNAPSHOT.jar --server.port=9090, or set the environment variable SERVER_PORT=9090. Profiles (application-dev.properties, application-prod.properties, activated with spring.profiles.active=prod) hold environment-specific settings such as database URLs. Never commit real passwords; read them from environment variables instead.
Testing the web layer#
The generated project already includes JUnit 5, Mockito and AssertJ (from the JUnit lesson). @WebMvcTest starts only the web layer, without a real server, and @MockitoBean replaces the service with a Mockito mock:
TaskService is plain Java, so you can test it with ordinary JUnit and no Spring at all: new TaskService(). For full end-to-end tests that start the whole application, use @SpringBootTest.
Packaging and running#
The Spring Boot Maven plugin builds a single executable "fat" JAR that contains your code, all dependencies and the embedded Tomcat. You can copy it to any machine with Java 21 and run it, or put it in a Docker image (./mvnw spring-boot:build-image builds one for you).
Where to go from here#
- Spring Data JPA + MySQL/PostgreSQL: replace the in-memory map with a database. You write an interface like
interface TaskRepository extends JpaRepository<Task, Long> {}, and Spring generates the JDBC code you wrote by hand in the JDBC lesson. - Validation and error handling:
@Valid, and@RestControllerAdvicewithProblemDetailfor consistent JSON error responses. - Spring Security: authentication, authorisation and JWT tokens.
- Actuator: health checks and metrics for production.
- Testcontainers: integration tests against a real database in Docker.
- The official guides at spring.io/guides, e.g. "Building a RESTful Web Service".
Common mistakes#
- Putting controllers or services in a package outside the main application's package. Component scanning won't find them, so you get 404s or "No qualifying bean" errors.
- Using field injection (
@Autowired private TaskService service;) instead of constructor injection: it's harder to test and can't befinal. - Forgetting the
Content-Type: application/jsonheader on POST requests (you'll get415 Unsupported Media Type). - Returning entities with sensitive fields (like password hashes) directly. Use record DTOs that expose only what clients need.
- Keeping mutable state in a bean with a plain
HashMap. Beans are shared by all requests, so they must be thread-safe. - Copying Spring Boot 2.x tutorials that use
javax.*imports. Since Boot 3, it'sjakarta.*.
What's next#
You've finished the Java course. From your first Hello, World! you've covered the language, OOP, collections, functional programming, concurrency, the JVM, databases, build tools, testing, modern Java and now Spring Boot. The best next step is to build something: a REST API for a project you care about, with a database, tests and a README. Push it to GitHub, keep practising, and enjoy being a Java developer!
Check your understanding
Quick quiz
1.What does
@SpringBootApplicationdo?2.Why is constructor injection the recommended way to receive dependencies?
3.A controller method returns
ResponseEntity.of(optional). What happens when the Optional is empty?
Finished reading?
Mark this lesson complete to track your progress.