My FeedDiscussionsHeadless CMS
New
Sign in
Log inSign up
Learn more about Hashnode Headless CMSHashnode Headless CMS
Collaborate seamlessly with Hashnode Headless CMS for Enterprise.
Upgrade ✨Learn more
Best way to create spring boot microservice using docker

Best way to create spring boot microservice using docker

Vikram Chaudhary's photo
Vikram Chaudhary
·May 1, 2022·

9 min read

Hello, In this article I will help you to develop your first Spring boot microservice. This is a step by step guide for creating a spring microservice. At the end of this article you should be able to write your first spring boot microservice.

In the further article I will host this service in the docker container using a docker image.

This article is divide in the following sections:

  1. Creating a Spring boot microservice using JPA.
  2. Creating an Docker image for the microservice.
  3. Running the application is an docker container.

Creating the Project Template

Go the spring initializer website and add the below dependencies.

  • Spring Web
  • Spring boot actuator
  • H2 database
  • Spring Data JPA

I have created the template as per the below image:

image.png

Apart from the above dependencies we need the lambok dependency. This is used to make the code less verbose and do what is supposed to do out of it.

The pom.xml file of the project should look like below.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.7</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.dotnetforall</groupId>
    <artifactId>loans</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>loans</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

The project structure

Below screenshot shows the project stucture. I will walk you through each and every component further in the article.

image.png

Import and Create a new workspace:

Create a new workspace in the Eclipse or IDE of your choice and import the downloaded template in the workspace.

Create the below packages in the project.

  • com.dotnetforall.loans.controller

  • com.dotnetforall.loans.model

  • com.dotnetforall.loans.repository

Modify the Loans application as shown in the below code. This is the main class for the spring boot microservice application. If we want to start the application, we need to come to this class and run it as Java project.

package com.dotnetforall.loans;

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

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@SpringBootApplication
@ComponentScans({ @ComponentScan("com.dotnetforall.loans.controller") })
@EnableJpaRepositories("com.dotnetforall.loans.repository")
@EntityScan("com.dotnetforall.loans.model")
public class LoansApplication {

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

}

Below is the explanation of the various annotations used in the class:

@SpringBootApplication: The annotation denotes the main class of the sprint project.

@ComponentScans: This annotation is used by Spring boot to find the annotated classes to convert them to bean. Spring boot will look in the folder provided as parameter for these classes.

@EnableJpaRepositories: Annotation to enable JPA repositories. Will scan the package of the annotated configuration class for Spring Data repositories by default.

@EntityScan: Annotation to scan and find the entities used in the project.

The controller class

Below is the code for our controller class.

The class contains two methods. One of them is the get method which simply returns the string.

The other one named getLoansDetails is the main method which returns the load details for a specific customer.

Both the methods are decorated with @PostMapping and @GetMapping along with the path of the URL methods as parameter.

package com.dotnetforall.loans.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import com.dotnetforall.loans.model.Customer;
import com.dotnetforall.loans.model.Loans;
import com.dotnetforall.loans.repository.LoansRepository;

@RestController
public class LoansController {

    @Autowired
    private LoansRepository loansRepository;

    @PostMapping("/myLoans")
    public List<Loans> getLoansDetails(@RequestBody Customer customer) {
        List<Loans> loans = loansRepository.findByCustomerIdOrderByStartDtDesc(customer.getCustomerId());
        if (loans != null) {
            return loans;
        } else {
            return null;
        }

    }

    @GetMapping("/sayHello")
    public String sayHello() {
        return "Hello there, this is your first web service";
    }
}

Annotations used in Controller class.

@RestController : Annotation used to specify the spring boot about the controllers in the project.

@Autowired: The annotation will find the LoansRepository class in the project and assign an instance to it.

@PostMapping and @GetMapping : Annotations used to define the GET and POST web methods of the microservice.

The model classes and the repository

The project has one main entity which is mapped to the DB structure of the project.

Below is the parameter class.

package com.dotnetforall.loans.model;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Getter @Setter @ToString
public class Customer {

    private int customerId;

}

And the entity class. Whenever We map the model class with @Entity annotation, the JPA framework treats the class as POJO representation of the Table structure.

@Getter and @Setter are the lambok annotations which can help you to avoid writing the Java boiler plate code.

package com.dotnetforall.accounts.model;

import java.time.LocalDate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

@Entity
@Getter @Setter @ToString
public class Accounts {

    @Column(name = "customer_id")
    private int customerId;
    @Column(name="account_number")
    @Id
    private long accountNumber;
    @Column(name="account_type")
    private String accountType;
    @Column(name = "branch_address")
    private String branchAddress;
    @Column(name = "create_dt")
    private LocalDate createDt;

}

Finally we have repository class which is used to fetch the data from the DB. Its all done by the JPA library used in the project. There is no need to write dedicated SQL statement to fetch the data.

This the power of JPA framework that just by the naming convention of the method, it fires the relative query.

package com.dotnetforall.accounts.repository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import com.dotnetforall.accounts.model.Accounts;

@Repository
public interface AccountsRepository extends CrudRepository<Accounts, Long> {

    Accounts findByCustomerId(int customerId);

}

The data store

In this project, I will be using the H2 DB to store the data. For the same purpose, I need to change the application.properties file under the resources folder as shown below.

The last line in the file denotes the port for the microservice.

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.h2.console.enabled=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true

server.port=8090

We need to have a data.sql file which will be executed once the project and compiled. The file is used to insert some sample data in the database.

DROP TABLE IF EXISTS loans;

CREATE TABLE `loans` (
  `loan_number` int NOT NULL AUTO_INCREMENT,
  `customer_id` int NOT NULL,
  `start_dt` date NOT NULL,
  `loan_type` varchar(100) NOT NULL,
  `total_loan` int NOT NULL,
  `amount_paid` int NOT NULL,
  `outstanding_amount` int NOT NULL,
  `create_dt` date DEFAULT NULL,
  PRIMARY KEY (`loan_number`)
);

INSERT INTO `loans` ( `customer_id`, `start_dt`, `loan_type`, `total_loan`, `amount_paid`, `outstanding_amount`, `create_dt`)
 VALUES ( 1, '2020-10-13', 'Home', 200000, 50000, 150000, '2020-10-13');

INSERT INTO `loans` ( `customer_id`, `start_dt`, `loan_type`, `total_loan`, `amount_paid`, `outstanding_amount`, `create_dt`)
 VALUES ( 1, '2020-06-06', 'Vehicle', 40000, 10000, 30000, '2020-06-06');

INSERT INTO `loans` ( `customer_id`, `start_dt`, `loan_type`, `total_loan`, `amount_paid`, `outstanding_amount`, `create_dt`)
 VALUES ( 1, '2021-02-14', 'Home', 50000, 10000, 40000, '2018-02-14');

INSERT INTO `loans` ( `customer_id`, `start_dt`, `loan_type`, `total_loan`, `amount_paid`, `outstanding_amount`, `create_dt`)
 VALUES ( 1, '2018-02-14', 'Personal', 10000, 3500, 6500, '2018-02-14');

Running the microservice

Right click on the LoansApplication.java and select "Run as Java Application".

Open the postman application to issue the POST command to the microservice.

You can see the result as shown in the below figure.

image.png

Deploying the microservice as Docker Image

Once we are able to run the microservice on our computer. Now come the turn to run the application as Docker container. For that we need to create an image for the microservice so that it can be uploaded to the docker hub. This image can be further used by anyone without doing any setup on their development workstation.

We need to have the docker installed on the workstation. You can find lots of article on how to install docker.

To create an image for the project we need to have a Dockerfile at the root location of the project. Note that this file is without any extension.

The Dockerfile create an image on the top of an existing image named 'lwieske/java-8'.

Next is the meta information about the image.

After that we need to upload the artifacts to the image. These are present in the target folder of our application.

And finally we need to provide the commands to run the application once the container is initialized.

#Start with a base image containing Java runtime
FROM lwieske/java-8 as build

#Information around who maintains the image
MAINTAINER dotnetforall.com

# Add the application's jar to the container
COPY target/loans-0.0.1-SNAPSHOT.jar loans-0.0.1-SNAPSHOT.jar

#execute the application
ENTRYPOINT ["java","-jar","/loans-0.0.1-SNAPSHOT.jar"]

Go to the project root folder in the command prompt. This should also be the location of Dockerfile. Run the below command.

docker build . -t dotnetforall/loans

dot(.) in the above command denotes the relative location of Dockerfile. Since I am running the above command from the same location.

-t -> Denotes the name we want to provide for this image.

You might encounter the error like below.

image.png

I have written an article for the same on my blog..

Once docker is ready with the image, you can see in the images list on your workstation using the below command

docker images

And you can see the output like below.

image.png

Running the container

We are almost there in our journey to host our first spring boot microservice in the docker container. We have already created a docker image.

We need to create a container out of that image and our microservice will be hosted in that container.

Below is the command to create a container.

docker run -p 8080:8090 dotnetforall/loans

The above command will host the application on 8080 port on our system. Though internally it will be running on the 8090 port as we have used that in our project.

The last parameter is the name of the image which is "dotnetforall/loans" in our case.

Once you run the above command, you can access the web API on port 8080.

Push the images to Docker hub

Once the image is ready, you can push the image to the docker hub repository. This will help other users to use your image without installing any other prerequsites to their local environment.

Here are the steps worked for me :

1) Login to the docker.

docker login -u {username}

2) Tag your image build

my image name here is : dotnetforall/loans and by default it has tag : latest and my username is : vikramvee as registered with docker cloud, and I created a public repository named : loans

so my personal repository becomes now : vikramvee/loans and I want to push my image with tag : latest .

I tagged as below :

docker tag dotnetforall/loans:latest vikramvee/loans:latest

Pushed the image to my personal docker repository as below:

docker push vikramvee/loans:latest

And the publicly available in my repository as shown in below screenshot.

image.png

Conclusion:

This article has been quite long as we have covered almost all the aspects of creating container based microservice. Docker has revolutionized the way we write and expose our service. This article could be your reference to quickly write a docker microservice.

Reference:

https://www.udemy.com/course/master-microservices-with-spring-docker-kubernetes/