Show List

Service Discovery Demo - Creating Microservices

For the service discovery demo, first we are going to create microservices "order" and "payment". 

We are going to use a multi module project structure. So the microservices will be modules in the project. Multi module project structure helps to easily maintain the code and allows to deploy the modules individually. All the dependencies are specified in the parent POM. Dependent modules can inherit the dependencies. Parent has the packaging as "pom". Child project can have any packaging.

Create Parent Project


Create a parent Spring Boot project with following dependencies: 
  • Lombok
  • Spring Web
  • Spring Data JPA
  • H2 Database
  • Cloud Bootstrap
You can go to the https://start.spring.io/ and add these dependencies to create Spring Boot starter project. You can also create the project in IntelliJ IDE after installing "Spring Assistant" plug in. After plugin is installed, go to create new project and click on "Spring Assistant" plugin. Then provide the group id, artifact id and then select the dependencies.
Delete the "src" folder from the parent project and update the packaging to "pom" in POM.xml.

Parent pom.xml:
<?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.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springcloud</groupId>
<artifactId>servicediscovery</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>servicediscovery</name>
<description>Demo project for Spring Cloud Service Discovery</description>
<properties>
<java.version>11</java.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
</properties>
<dependencies>
<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>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>

Create "order" microservices (module)

Right click on the project and create a new maven module. Under the parent field, select parent project name and click finish.
Create the model, Dao control and main application class as below:
Order.java model class:
package com.springcloud.servicediscovery.order.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Table(name = "ORDERTBL")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int orderId;
private String itemName;
private int quantity;
private double price;
}
OrderRepo.java:
package com.springcloud.servicediscovery.order.dao;

import com.springcloud.servicediscovery.order.model.Order;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface OrderRepo extends CrudRepository<Order, Integer> {}
OrderController.java:
package com.springcloud.servicediscovery.order.controller;

import com.springcloud.servicediscovery.order.dao.OrderRepo;
import com.springcloud.servicediscovery.order.model.Order;
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 java.util.List;

@RestController
public class OrderController {
@Autowired
private OrderRepo repo;

@GetMapping("/orders")
private List<Order> getAllStudents(){
return (List<Order>) repo.findAll();
}

@PostMapping("/orders")
private Order addOrder(@RequestBody Order newOrder){
return repo.save(newOrder);
}
}
OrderApplication.java :
package com.springcloud.servicediscovery.order;

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

@SpringBootApplication
public class OrderApplication {

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

}
application.yml file in the resources folder has properties for server port and to enable h2 console
server:
port: 9001
spring:
h2:
console:
enabled: true
banner.txt file in the resources folder has banner to display on the console when application starts instead of the default Spring Boot banner. Such banner was created from website https://devops.datenkollektiv.de/banner.txt/index.html.
 ,-----.             ,--.
' .-. ' ,--.--. ,-| | ,---. ,--.--.
| | | | | .--' ' .-. | | .-. : | .--'
' '-' ' | | \ `-' | \ --. | |
`-----' `--' `---' `----' `--'
When the spring boot module is run we can see the h2 connection details in the log:
"C:\Program Files\Java\jdk-11.0.15\bin\java.exe" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\lib\idea_rt.jar=57472:C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2021.2\bin" -Dfile.encoding=UTF-8 -classpath C:\Users\mail2\Downloads\servicediscovery\order\target\classes;D:\.m2\repository\org\springframework\boot\spring-boot-starter-data-jpa\2.7.5\spring-boot-starter-data-jpa-2.7.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-aop\2.7.5\spring-boot-starter-aop-2.7.5.jar;D:\.m2\repository\org\springframework\spring-aop\5.3.23\spring-aop-5.3.23.jar;D:\.m2\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-jdbc\2.7.5\spring-boot-starter-jdbc-2.7.5.jar;D:\.m2\repository\com\zaxxer\HikariCP\4.0.3\HikariCP-4.0.3.jar;D:\.m2\repository\org\springframework\spring-jdbc\5.3.23\spring-jdbc-5.3.23.jar;D:\.m2\repository\jakarta\transaction\jakarta.transaction-api\1.3.3\jakarta.transaction-api-1.3.3.jar;D:\.m2\repository\jakarta\persistence\jakarta.persistence-api\2.2.3\jakarta.persistence-api-2.2.3.jar;D:\.m2\repository\org\hibernate\hibernate-core\5.6.12.Final\hibernate-core-5.6.12.Final.jar;D:\.m2\repository\org\jboss\logging\jboss-logging\3.4.3.Final\jboss-logging-3.4.3.Final.jar;D:\.m2\repository\net\bytebuddy\byte-buddy\1.12.18\byte-buddy-1.12.18.jar;D:\.m2\repository\antlr\antlr\2.7.7\antlr-2.7.7.jar;D:\.m2\repository\org\jboss\jandex\2.4.2.Final\jandex-2.4.2.Final.jar;D:\.m2\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\.m2\repository\org\hibernate\common\hibernate-commons-annotations\5.1.2.Final\hibernate-commons-annotations-5.1.2.Final.jar;D:\.m2\repository\org\glassfish\jaxb\jaxb-runtime\2.3.7\jaxb-runtime-2.3.7.jar;D:\.m2\repository\org\glassfish\jaxb\txw2\2.3.7\txw2-2.3.7.jar;D:\.m2\repository\com\sun\istack\istack-commons-runtime\3.0.12\istack-commons-runtime-3.0.12.jar;D:\.m2\repository\com\sun\activation\jakarta.activation\1.2.2\jakarta.activation-1.2.2.jar;D:\.m2\repository\org\springframework\data\spring-data-jpa\2.7.5\spring-data-jpa-2.7.5.jar;D:\.m2\repository\org\springframework\data\spring-data-commons\2.7.5\spring-data-commons-2.7.5.jar;D:\.m2\repository\org\springframework\spring-orm\5.3.23\spring-orm-5.3.23.jar;D:\.m2\repository\org\springframework\spring-context\5.3.23\spring-context-5.3.23.jar;D:\.m2\repository\org\springframework\spring-tx\5.3.23\spring-tx-5.3.23.jar;D:\.m2\repository\org\springframework\spring-beans\5.3.23\spring-beans-5.3.23.jar;D:\.m2\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\.m2\repository\org\springframework\spring-aspects\5.3.23\spring-aspects-5.3.23.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-web\2.7.5\spring-boot-starter-web-2.7.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter\2.7.5\spring-boot-starter-2.7.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot\2.7.5\spring-boot-2.7.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.5\spring-boot-autoconfigure-2.7.5.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-logging\2.7.5\spring-boot-starter-logging-2.7.5.jar;D:\.m2\repository\ch\qos\logback\logback-classic\1.2.11\logback-classic-1.2.11.jar;D:\.m2\repository\ch\qos\logback\logback-core\1.2.11\logback-core-1.2.11.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-to-slf4j\2.17.2\log4j-to-slf4j-2.17.2.jar;D:\.m2\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\.m2\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\.m2\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\.m2\repository\org\yaml\snakeyaml\1.30\snakeyaml-1.30.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-json\2.7.5\spring-boot-starter-json-2.7.5.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-databind\2.13.4.2\jackson-databind-2.13.4.2.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.4\jackson-annotations-2.13.4.jar;D:\.m2\repository\com\fasterxml\jackson\core\jackson-core\2.13.4\jackson-core-2.13.4.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.4\jackson-datatype-jdk8-2.13.4.jar;D:\.m2\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.4\jackson-datatype-jsr310-2.13.4.jar;D:\.m2\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.4\jackson-module-parameter-names-2.13.4.jar;D:\.m2\repository\org\springframework\boot\spring-boot-starter-tomcat\2.7.5\spring-boot-starter-tomcat-2.7.5.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-core\9.0.68\tomcat-embed-core-9.0.68.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.68\tomcat-embed-el-9.0.68.jar;D:\.m2\repository\org\apache\tomcat\embed\tomcat-embed-websocket\9.0.68\tomcat-embed-websocket-9.0.68.jar;D:\.m2\repository\org\springframework\spring-web\5.3.23\spring-web-5.3.23.jar;D:\.m2\repository\org\springframework\spring-webmvc\5.3.23\spring-webmvc-5.3.23.jar;D:\.m2\repository\org\springframework\spring-expression\5.3.23\spring-expression-5.3.23.jar;D:\.m2\repository\org\springframework\cloud\spring-cloud-starter\3.1.4\spring-cloud-starter-3.1.4.jar;D:\.m2\repository\org\springframework\cloud\spring-cloud-context\3.1.4\spring-cloud-context-3.1.4.jar;D:\.m2\repository\org\springframework\security\spring-security-crypto\5.7.4\spring-security-crypto-5.7.4.jar;D:\.m2\repository\org\springframework\cloud\spring-cloud-commons\3.1.4\spring-cloud-commons-3.1.4.jar;D:\.m2\repository\org\springframework\security\spring-security-rsa\1.0.11.RELEASE\spring-security-rsa-1.0.11.RELEASE.jar;D:\.m2\repository\org\bouncycastle\bcpkix-jdk15on\1.69\bcpkix-jdk15on-1.69.jar;D:\.m2\repository\org\bouncycastle\bcprov-jdk15on\1.69\bcprov-jdk15on-1.69.jar;D:\.m2\repository\org\bouncycastle\bcutil-jdk15on\1.69\bcutil-jdk15on-1.69.jar;D:\.m2\repository\com\h2database\h2\2.1.214\h2-2.1.214.jar;D:\.m2\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;D:\.m2\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\.m2\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;D:\.m2\repository\org\springframework\spring-core\5.3.23\spring-core-5.3.23.jar;D:\.m2\repository\org\springframework\spring-jcl\5.3.23\spring-jcl-5.3.23.jar com.springcloud.servicediscovery.order.OrderApplication
 ,-----.             ,--.
'  .-.  ' ,--.--.  ,-|  |  ,---.  ,--.--.
|  | |  | |  .--' ' .-. | | .-. : |  .--'
'  '-'  ' |  |    \ `-' | \   --. |  |
 `-----'  `--'     `---'   `----' `--'
2022-10-26 16:00:50.403  INFO 9960 --- [           main] c.s.s.order.OrderApplication             : Starting OrderApplication using Java 11.0.15 on sm15 with PID 9960 (C:\Users\mail2\Downloads\servicediscovery\order\target\classes started by mail2 in C:\Users\mail2\Downloads\servicediscovery)
2022-10-26 16:00:50.409  INFO 9960 --- [           main] c.s.s.order.OrderApplication             : No active profile set, falling back to 1 default profile: "default"
2022-10-26 16:00:51.462  INFO 9960 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
2022-10-26 16:00:51.536  INFO 9960 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 62 ms. Found 1 JPA repository interfaces.
2022-10-26 16:00:51.813  INFO 9960 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=09d11aea-0332-3c92-b042-65599ff3a877
2022-10-26 16:00:52.642  INFO 9960 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 9001 (http)
2022-10-26 16:00:52.643  INFO 9960 --- [           main] o.a.catalina.core.AprLifecycleListener   : An older version [1.2.28] of the Apache Tomcat Native library is installed, while Tomcat recommends a minimum version of [1.2.30]
2022-10-26 16:00:52.644  INFO 9960 --- [           main] o.a.catalina.core.AprLifecycleListener   : Loaded Apache Tomcat Native library [1.2.28] using APR version [1.7.0].
2022-10-26 16:00:52.644  INFO 9960 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR capabilities: IPv6 [true], sendfile [true], accept filters [false], random [true], UDS [true].
2022-10-26 16:00:52.644  INFO 9960 --- [           main] o.a.catalina.core.AprLifecycleListener   : APR/OpenSSL configuration: useAprConnector [false], useOpenSSL [true]
2022-10-26 16:00:52.647  INFO 9960 --- [           main] o.a.catalina.core.AprLifecycleListener   : OpenSSL successfully initialized [OpenSSL 1.1.1k  25 Mar 2021]
2022-10-26 16:00:52.658  INFO 9960 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2022-10-26 16:00:52.658  INFO 9960 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.68]
2022-10-26 16:00:52.854  INFO 9960 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2022-10-26 16:00:52.855  INFO 9960 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 2360 ms
2022-10-26 16:00:52.905  INFO 9960 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2022-10-26 16:00:53.220  INFO 9960 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2022-10-26 16:00:53.240  INFO 9960 --- [           main] o.s.b.a.h2.H2ConsoleAutoConfiguration    : H2 console available at '/h2-console'. Database available at 'jdbc:h2:mem:a9fb7432-5405-48d5-b897-d36cbba23d2d'
2022-10-26 16:00:53.527  INFO 9960 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
2022-10-26 16:00:53.607  INFO 9960 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.12.Final
2022-10-26 16:00:53.862  INFO 9960 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
2022-10-26 16:00:54.063  INFO 9960 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
2022-10-26 16:00:54.881  INFO 9960 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2022-10-26 16:00:54.893  INFO 9960 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2022-10-26 16:00:55.317  WARN 9960 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2022-10-26 16:00:56.187  INFO 9960 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 9001 (http) with context path ''
2022-10-26 16:00:56.518  INFO 9960 --- [           main] c.s.s.order.OrderApplication             : Started OrderApplication in 7.321 seconds (JVM running for 8.003)
2022-10-26 16:03:42.156  INFO 9960 --- [nio-9001-exec-9] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-10-26 16:03:42.156  INFO 9960 --- [nio-9001-exec-9] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-10-26 16:03:42.158  INFO 9960 --- [nio-9001-exec-9] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms

In the log we see that:
  • H2 console available at '/h2-console'
  • Database available at 'jdbc:h2:mem:a9fb7432-5405-48d5-b897-d36cbba23d2d'
  • Tomcat started on port(s): 9001
So we can access the H2 database by going to the URL localhost:9001/h2-console and then paste the jdbc:h2:mem:a9fb7432-5405-48d5-b897-d36cbba23d2d in the JDBC URL field. Click on connect.
Request can be sent through Postman to create the order:
Inserted data can also be verified from the database console:

Create "payment" microservices (module)

Follow the same steps to create the "payment" microservice as below:

Payment.java model:
package com.springcloud.servicediscovery.paymnt.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;

@Entity
@Table
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int paymentId;
private int orderId;
private double paymentAmt;
}
PaymentRepo.java :
package com.springcloud.servicediscovery.paymnt.dao;

import com.springcloud.servicediscovery.paymnt.model.Payment;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface PaymentRepo extends CrudRepository<Payment, Integer> {}
PaymentController.java :
package com.springcloud.servicediscovery.paymnt.controller;

import com.springcloud.servicediscovery.paymnt.dao.PaymentRepo;
import com.springcloud.servicediscovery.paymnt.model.Payment;
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 java.util.List;

@RestController
public class PaymentController {
@Autowired
private PaymentRepo repo;

@GetMapping("/payments")
private List<Payment> getAllPayments(){
return (List<Payment>) repo.findAll();
}

@PostMapping("/payments")
private Payment addPayment(@RequestBody Payment newPayment){
return repo.save(newPayment);
}
}
PaymentApplication.java
package com.springcloud.servicediscovery.paymnt;

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

@SpringBootApplication
public class PaymentApplication {

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

}
application.yml
server:
port: 9002
spring:
h2:
console:
enabled: true
banner.txt
,------.                                                   ,--.
| .--. ' ,--,--. ,--. ,--. ,--,--,--. ,---. ,--,--, ,-' '-.
| '--' | ' ,-. | \ ' / | | | .-. : | \ '-. .-'
| | --' \ '-' | \ ' | | | | \ --. | || | | |
`--' `--`--' .-' / `--`--`--' `----' `--''--' `--'
`---'
H2 connection details for payment service can also be obtained from the console when the application is run.

Source code:
https://github.com/it-code-lab/spring-cloud-servicediscovery

    Leave a Comment


  • captcha text