Docker is an open source platform that lets you build application container images, which developers can then use to create, manage, and run containers. Docker enhances the efficiency of the development lifecycle while also making it more predictable, maximizing your productivity.

Meanwhile, Spring Boot is a popular Java framework for creating production-grade applications. Dockerizing Spring Boot apps has become the norm for modern application development, simplifying the process of packaging and deploying Spring Boot applications into containers that can be executed on any Docker-enabled machine. This makes it easy to move your application from one environment to another (ie from development to production).

In addition, Docker allows you to easily scale your application by running multiple instances of your containerized application. This can be done using tools such as Kubernetes, which provides a powerful platform for managing containerized applications.

In this tutorial, you will create a sample microservice application with Spring Boot and run it with Docker. You will learn that containerization can help increase scalability and portability in a microservices architecture. In addition, you’ll develop unit tests of the microservice application to better understand the importance of code coverage.

All the code for this tutorial is available in this GitHub repo.

Setting Up Your Spring Boot Project

Before you begin this tutorial, you need to install the following:

In this tutorial, you’ll be setting up a Spring Boot project from scratch using the Spring Boot command line tool (CLI). This CLI helps you bootstrap a new Spring Boot project in no time. Refer to the official documentation to install the CLI for your operating system.

Please note: The Spring Boot CLI version 3.0.5 on Windows was used here.

Once installed, you can verify the installation by executing the command from the bin directory of Spring Boot CLI’s installation path:

.\spring --version

Creating a New Spring Boot Project

Now that you’ve installed the Spring Boot CLI, it’s time to create a new Spring Boot project for your microservice application. From the bin directory of Spring Boot CLI’s installation path, execute the following command:

.\spring init --boot-version=2.7.11 --build=maven --java-version=17 --dependencies=web,lombok,postgresql,data-jpa --packaging=jar

This command tells your system to create a Java 17–based Spring Boot application with a Maven-compatible build definition and other required dependencies.

You should see a new ZIP file named created in the same directory. This ZIP file contains the essential files with a folder structure for the microservice application that you’re going to build.

Next, you need to create a new directory named getting-started-with-springboot-and-docker in any location of your choice on the host machine. Extract and copy the contents in the ZIP file to the newly created getting-started-with-springboot-and-docker directory.

Configuring Basic Properties in

Now that your basic project files are ready, open the project in IntelliJ (or your favorite Java IDE) and create the file in the Spring Boot project path .\getting-started-with-springboot-and-docker\src\main\resources\. Use this file to configure the basic properties of your application by pasting the following code in


Building a Microservice with Spring Boot

Before we continue to develop this application, take a minute to understand what a microservices architecture is and why that matters.

Microservices architecture is a software design approach where a large monolithic application is broken down into smaller, independent services that can be developed, deployed, and scaled independently of each other. Each microservice is designed to perform a specific function and communicates with other microservices through well-defined APIs. This approach enables faster development, deployment, and testing, as well as better scalability and resilience. However, it also requires careful management of interservice communication and data consistency.

Now that you know microservices communicate through APIs, move on to building REST APIs with Spring Boot.

Create a Controller Package

In this example, you are working with a product microservices application that holds data about products in a retail store. Here, you create REST APIs to fetch the details about the products stored in the microservice application’s database, which we use PostgreSQL for.

Start by creating a Java package named controller in your project’s path, src/main/java/com/example/gettingstartedwithspringbootanddocker. Then create a class file named and paste the following code into it:

package com.example.gettingstartedwithspringbootanddocker.controller;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import com.example.gettingstartedwithspringbootanddocker.model.Products;
import com.example.gettingstartedwithspringbootanddocker.service.ProductsService;

public class ProductsController {

   ProductsService productsService;

   List<Products> getAllProducts() {
       return productsService.getAllProducts();

   ResponseEntity<Optional<Products>> getProductById(@PathVariable Long productId) {
       Optional<Products> product = productsService.findByProductId(productId);
       if (product.isEmpty()) {
           return ResponseEntity.notFound().build();
       return ResponseEntity.ok(product);

A Controller class is responsible for handling incoming HTTP requests and returning an HTTP response. The Controller class typically receives input from the user or from other systems, performs any necessary validation or processing, interacts with the service layer to perform business logic, and returns an appropriate response to the client.

The ProductsController class has two REST endpoints: one to get all the products and another to get a product based on its ID. These endpoints make use of the service class methods to perform business logic. In the previous code snippet, you can see that the @Autowired annotation is applied to a field named productsService and a ProductsService type.

The @Autowired annotation is used for automatic dependency injection in Spring and allows Spring to automatically resolve and inject the dependencies required by a class. Next, you’ll learn more about the service class as you create one.

Create a Service Class

Your ProductsController class depends on the service class named ProductsService to handle the backend business logic. For this purpose, you can create a class in a package named service in the project path src/main/java/com/example/gettingstartedwithspringbootanddocker/. Paste the following code in the ProductsService class file:

package com.example.gettingstartedwithspringbootanddocker.service;

import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.gettingstartedwithspringbootanddocker.model.Products;
import com.example.gettingstartedwithspringbootanddocker.repository.ProductsRepository;

public class ProductsService {

   ProductsRepository productsRepository;

   public List<Products> getAllProducts() {

       return productsRepository.findAll();

   public Optional<Products> findByProductId(Long productId) {
       return productsRepository.findById(productId);

The Service class uses a Repository class to interact with the database. You’ll define the Repository class next.

Create a Repository Class

Create the class in a package named repository in the project path src/main/java/com/example/gettingstartedwithspringbootanddocker/. A repository class provides an interface to store and retrieve data from a database. Edit the class by pasting the following code into it:

package com.example.gettingstartedwithspringbootanddocker.repository;

import com.example.gettingstartedwithspringbootanddocker.model.Products;
import org.springframework.stereotype.Repository;

public interface ProductsRepository extends JpaRepository<Products, Long> {


In Spring, the @Repository annotation indicates that a class is a repository that is responsible for data access and persistence operations. It’s typically applied to classes that interact with a database or other data sources.

In the previous code, the ProductsRepository interface extends the JpaRepository interface, which is a generic interface provided by Spring Data JPA. The Spring Data JPA is an abstraction over the Java Persistence API (JPA). By extending JpaRepository, the ProductsRepository interface inherits several CRUD (Create, Read, Update, Delete) methods, as well as additional querying capabilities provided by Spring Data JPA. The generic types used in JpaRepository<Products, Long> specify the entity type (Products) and the type of the entity’s primary key (Long). In this case, it indicates that the ProductsRepository interface is specifically designed to handle persistence operations for the Products entity, where the primary key is of type Long.

Create a Products Model Class

The ProductsRepository class acts on the Products table in the database. You need to create a model class for the Products table to define the relevant table and field mapping on the Java application side. Create the class in a package named model in the project path src/main/java/com/example/gettingstartedwithspringbootanddocker/. Paste the following code in the Products class file:

package com.example.gettingstartedwithspringbootanddocker.model;

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

public class Products {
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private Long id;

   private String name;

   private String category;

   private float price;

This code snippet makes use of several annotations including the following:

  • @Entity marks the class as an entity, representing a table in the database.
  • @Table(name="products") specifies the table name (ie products) to which the entity is mapped.
  • @Getter generates the getter methods for the class’s fields.
  • @Setter generates the setter methods for the class’s fields.
  • @Id marks the field as the primary key of the entity.
  • @GeneratedValue(strategy = GenerationType.IDENTITY) specifies that the primary key values are automatically generated by the database using an identity strategy.
  • @Column maps the field to a column in the table

Create Database Table Script Files

Now that you’ve created the Java application code for your microservice application, you need to create database script files in the resources location (src\main\resources) where the of your Java project exists. These scripts are used to create the Products table structure in the database and insert data into it when the application gets initialized.

Create a file named schema.sql and paste the following data definition language (DDL) code into it:

CREATE TABLE products (
 name VARCHAR(255) NOT NULL,
 category TEXT,
 price DECIMAL(10,2) NOT NULL

Then create another file named import.sql and paste the following code into it:

INSERT INTO products (id, name,  category,  price) VALUES (1, 'Closeup Toothpaste', 'Toothpaste', 78) ;
INSERT INTO products (id, name,  category,  price) VALUES (2, 'Colgate Toothpaste', 'Toothpaste', 80) ;
INSERT INTO products (id, name,  category,  price) VALUES (3, 'Pepsodent Toothpaste', 'Toothpaste', 82) ;

Spring Boot takes care of automatically reading these script files and loading them into the database configured in the file.

And now, you’ve finished creating the sample microservices application with Spring Boot.

Building the Spring Boot Microservice Application

To build the JAR of the Spring Boot microservice application, run the following command in your terminal:

cd getting-started-with-springboot-and-docker
mvnw clean install

After successful execution, you should be able to see the application JAR created in a directory named target.

Running the Spring Boot Application with Docker

To run the Spring Boot application with Docker, download and install the Docker Desktop software. Installing Docker Desktop gets you both Docker and Docker Compose.

Docker Compose is a tool that developers use to specify and deploy multicontainer Docker applications on a single machine. With Docker Compose, you can define the services, networks, and volumes required for your application in a single docker-compose.yml file. This file specifies how each container image should be built, configured, and linked together.

Once Docker Desktop is up and running, you can verify that it’s working by opening a terminal or command prompt and running the following command:

docker version
docker compose version

Creating a Dockerfile for your Spring Boot Project

After installing Docker, you need to create a Dockerfile for your Spring Boot application. A Dockerfile is a text file that contains a set of instructions that are used to build a Docker image.

Create a file named Dockerfile in the project directory getting-started-with-springboot-and-docker and paste the following code into it:

# Use an official OpenJDK runtime as a parent image
FROM openjdk:17-jdk-alpine

# Set the working directory to /app

# Copy the executable jar file and the file to the container
COPY target/getting-started-with-springboot-and-docker-0.0.1-SNAPSHOT.jar /app/

# Set the command to run the Spring Boot application
CMD ["java", "-jar", "getting-started-with-springboot-and-docker-0.0.1-SNAPSHOT.jar"]

This Dockerfile contains instructions, including the following:

  • The base image openjdk:18-jdk-alpine to use for the container
  • The process to set the working directory in the container
  • The instructions to copy the application JAR into the container
  • The command to start the application

Creating a Docker Compose YAML File

Since your microservice application requires a database to persist the Products data, you need to work with two services: a PostgreSQL database and the microservice application. You can create a docker-compose.yaml file in the project directory getting-started-with-springboot-and-docker to hold the instructions to start and manage both these services.

Paste the following code in the docker-compose.yaml file:

version: '3.5'

   container_name: postgres
   image: postgres:15.1
     POSTGRES_USER: postgres
     POSTGRES_PASSWORD: postgres
     POSTGRES_DB: product
     - "5432:5432"

   container_name: product-service
   image: product-service
     - "8080:8080"
   restart: "always"

The previous docker-compose file defines two services: a PostgreSQL database service (postgres) and a custom service (product-service). It sets up the necessary environment variables and port mappings for each service and specifies the Docker images to use. For more information on these specifications check out the official documentation of Docker Compose

Building and Running a Docker Container for Your Microservice

Run the following command to build the Docker container image in your terminal:

cd getting-started-with-springboot-and-docker
docker build -t product-service.

Once the image is built, you can run the following command to start the containers:

docker compose -f docker-compose.yaml up -d

Access the following URLs in a browser or REST client to test if the REST APIs you created are working:


You should see a response like this:

	"id": 1,
	"name": "Closeup Toothpaste",
	"category": "Toothpaste",
	"price": 78.0
}, {
	"id": 2,
	"name": "Colgate Toothpaste",
	"category": "Toothpaste",
	"price": 80.0
}, {
	"id": 3,
	"name": "Pepsodent Toothpaste",
	"category": "Toothpaste",
	"price": 82.0

Unit Testing Microservices in Spring Boot

Now that your entire sample microservice is ready, it’s time to develop some unit tests. Unit tests ensure individual classes or components work as intended in isolation. They’re usually automated tests designed to test the smallest piece of code possible.

In the context of microservices, unit tests are used to test the individual microservices in isolation, without relying on other microservices or external dependencies, such as databases.

In the case of your microservice, the backend logic is present in the service class ProductsService, and you need to unit test it. To do so, create a test package named service in the project’s test package path, src/test/java/com/example/gettingstartedwithspringbootanddocker. Then create a class file named and paste the following code into it:

package com.example.gettingstartedwithspringbootanddocker.service;

import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import com.example.gettingstartedwithspringbootanddocker.model.Products;
import com.example.gettingstartedwithspringbootanddocker.repository.ProductsRepository;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;

class ProductsServiceTest {
    private ProductsRepository productsRepository;

    private ProductsService productsService;

     * Method under test: {@link ProductsService#getAllProducts()}
    void testGetAllProducts() {
        // Arrange
        ArrayList<Products> productsList = new ArrayList<>();

        // Act
        List<Products> actualAllProducts = productsService.getAllProducts();

        // Assert
        assertSame(productsList, actualAllProducts);

     * Method under test: {@link ProductsService#findByProductId(Long)}
    void testFindByProductId() {
        // Arrange
        Products products = new Products();
        products.setName("Closeup Toothpaste");
        Optional<Products> ofResult = Optional.of(products);
        when(productsRepository.findById((Long) any())).thenReturn(ofResult);

        // Act
        Optional<Products> actualFindByProductIdResult = productsService.findByProductId(1L);

        // Assert
        assertSame(ofResult, actualFindByProductIdResult);
        verify(productsRepository).findById((Long) any());

You can see that the getAllProducts and findByProductId methods of the actual ProductsService class are being tested. The ProductsRepository class is mocked to simulate the database interaction without connecting to the real database.

Understanding Code Coverage

Code coverage is a measure of how much of the source code of a software application is executed during testing. It’s an important metric to ensure that the application has been thoroughly tested and that all parts of the code have been exercised. High code coverage is desirable, as it increases confidence in the quality of the software and reduces the risk of bugs and issues. So how can you incorporate code coverage into this Spring Boot project?

The answer is simple. Add the following code to your project’s pom.xml file:


The jacoco plugin addition to the project allows you to autogenerate code coverage reports when the tests are executed.

Tests Execution and Code Coverage Report Generation

To execute your tests and generate code coverage reports, execute the following commands:

docker compose -f docker-compose.yaml up -d postgres
mvnw clean install

This docker compose command starts the PostgreSQL database for your initialized application. The mvnw clean install command clears the target directory if it exists and builds the application JAR by executing the tests. As part of the execution, it also uses the jacoco maven plugin to generate code coverage reports in the target/site/jacoco/ directory.

You can access the index.html file in that jacoco directory to see your project’s code coverage:

JaCoCo code coverage report

In a simple microservice application like the one where you only have a few classes to deal with, this process is relatively easy. However, in an enterprise-grade microservice application, you have to deal with developing more classes and, subsequently, more unit tests for all those classes. This can easily become overwhelming and take a lot of your team’s resources.

To reduce your time spent on test class development and increase code coverage, it’s a good idea to use an AI-powered technology platform like Diffblue that can help automatically generate unit tests for your application.

Diffblue Cover writes Java unit tests for you completely autonomously, with zero effort on your part. They always compile and reflect the behavior of your code today, to help you spot regressions when you make changes. A free IntelliJ plugin can be used to write tests while you’re working on specific code; a more powerful CLI version lets you write and update tests across an entire Java project, and make the process an integrated part of your CI pipeline.

Diffblue Cover Reports expands on the code coverage reporting provided by JaCoCo to give you more insight into where risks might lie and why some code is tested.


Spring Boot is an amazing open source framework to develop product-grade Java applications. Bundling it as Docker images and running it in containers will help you gain flexibility and scalability in any environment.

In this tutorial, you developed a sample microservice with Spring Boot and executed the application using Docker technology. In addition, you learned about the importance of code coverage and how to implement it in your application.

We also looked at how important unit tests are when you’re getting started with Spring Boot and Docker (just like when you’re writing any other code!) to ensure quality and avoid regressions as you make changes. But writing them is slow, repetitive and tedious compared to the more interesting work of getting your Docker-based microservice up and running. That’s where Diffblue Cover comes in.

Try Cover today to see what it can do for your Java projects.