DEV Community

Abdelouahedd
Abdelouahedd

Posted on

**Microservices with Spring Boot**

Microservices with Spring Boot

In this article we will cover the basic of microservices with spring boot using spring cloud.
I will explain some basic concept of microservice with a small demonstration.

Introduction of microservices :

Microservices mean separate the project to small services,building small,self-contained,ready to run application.
In monolithic architecture we have one project that contains multiple components that becomes a large application that has many disadvantages.
For example, if a monolithic application down, the entire application will be down. Even it’s difficult to maintain a large monolithic application.

Microservices break a large application to different smaller part, so it is easy to detect the problem and maintain it. and also if a component goes down
it will not affect the whole application.

Architecture

communication services
Our goal is create microservices that communicate and pass information without intervention.
In the architecture, we create two service customers and invoices using spring boot, those services are communicating via a REST endpoint, and for consuming data as client we use Spring Cloud OpenFeign that create a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotation.

@FeignClient(name = "CUSTOMER-SERVICE")
public interface CustomerServiceClient {
  @GetMapping("api/customers/{id}")
  Customer getCustomerById(@PathVariable("id") Integer id);

  @GetMapping("api/customers")
  List<Customer> getCustomers();
}
Enter fullscreen mode Exit fullscreen mode

example of OpenFeign client interface for consume the end point of consumer service.
for integrate openFeign we have to add dependency to the project

    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
Enter fullscreen mode Exit fullscreen mode

and after that we enable it by using the annotation @EnableFeignClients in a configure class or main class.

@SpringBootApplication
@EnableFeignClients
public class InvoiceApplication {
  public static void main(String[] args) {
    SpringApplication.run(InvoiceApplication.class, args);
  }
}
Enter fullscreen mode Exit fullscreen mode

Applications - Service 1

Customers service created to manage customers of our application, and for that we create a spring boot application using spring initializer, with H2 database with spring Data for manage persist data and spring web for create the end points.

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
      <groupId>com.h2database</groupId>
      <artifactId>h2</artifactId>
      <scope>runtime</scope>
    </dependency>
    <dependency>
Enter fullscreen mode Exit fullscreen mode

and finally we have the service Cutomers

customer project

we have to add some configuration propertie to application.yml in ressource folder

server:
  port: 8089
spring:
  application:
    name: CUSTOMER-SERVICE
  h2:
    console:
      enabled: true
  datasource:
    url: jdbc:h2:mem:customer-db
    driverClassName: org.h2.Driver
    username: sa
  jpa:
    database-platform: org.hibernate.dialect.H2Dialect
    hibernate:
      ddl-auto: update
    show-sql: true
Enter fullscreen mode Exit fullscreen mode

we also need some data in our database to retrieve anything with our method above. An embedded database will spin up when the application starts and be destroyed when the application terminates. So, we need to populate the database each time the application starts. We could load in external data each time, but for simplicity/demo purposes, we will create a bean with hard-coded Customer objects to save.

@Bean
  CommandLineRunner commandLineRunner(CustomerService customerService) {
    return arguments -> {
      CustomerRequest customer = CustomerRequest.builder()
        .email("john-doe@gmail.com")
        .firstName("john")
        .lastName("doe")
        .build();
      CustomerRequest customer1 = CustomerRequest.builder()
        .email("Alix-bob@gmail.com")
        .firstName("Bob")
        .lastName("Alix")
        .build();
      Customer customer2 = customerService.saveCustomer(customer);
      Customer customer3 = customerService.saveCustomer(customer1);
      log.info("Saved customer {}", customer2);
      log.info("Saved customer {}", customer3);
    };
  }
Enter fullscreen mode Exit fullscreen mode

A CommandLineRunner runs when the application starts, so this bean executes early in the startup

Applications - Service 2

In Service 2, we have to create same project as customer but we need some other dependency like OpenFeigh client as I munchin in the architecture part.

Invoices project

and again in cutomer service we have to define a cutomer class because we need the frontend application to recognize and map the same objects our backend service uses.

@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
  private Integer id;
  private String firstName;
  private String lastName;
  private String email;
}
Enter fullscreen mode Exit fullscreen mode

Service2 does not interact directly with the database, so it only needs the domain class to ensure data being passed matches what our backend services expects and returns

Test

AFter creating the two service,
Start each of the applications, either through your IDE or via the command line and we can acces to customer service in http://localhost:8089/api/customers and invoice service by url http://localhost/8081/api/invoices

Service discovery with Eureka servers.

The Discovery server used to register all services after they go to live. Then it will be easy to find out the service from the registry. When a service registers with eureka it will provide the metadata like host, port and health indicator parameters to the client to connect.
We have to create a new service call eureka-server and we have to add dependecy

    <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
Enter fullscreen mode Exit fullscreen mode

We need to add annotation @EnableEurekaServer to the application main class. This annotation will enable the services registration with the eureka server.

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(EurekaServerApplication.class, args);
  }
}
Enter fullscreen mode Exit fullscreen mode

Now we need to define some properties to application.properties file.

spring:
  application:
    name: eureka-server
server:
  port: 8761
eureka:
  client:
    fetch-registry: false
    register-with-eureka: false
Enter fullscreen mode Exit fullscreen mode

we set the register-with-eureka to false so that the service euroka not regsiter it self on the discovery.
After we change the application.yml for the cutomers and invoices service and add

    eureka:
    client:
      service-url:
        defaultZone: http://localhost:8761/eureka
      fetch-registry: true
      register-with-eureka: true
Enter fullscreen mode Exit fullscreen mode

so this configuration give the service the ability to register in the discovery euroka.

API Gateway

What’s the real API Gateway meaning? An API gateway is an API management tool that exists between a client and a collection of backend services. An API gateway acts as a reverse proxy to accept all application programming interface (API) calls, aggregate the various services required to fulfil the requests and then return the appropriate result.

The Main Function of an API Gateway!

An API gateway that takes an application user’s request, routes it to one or more backend services, gathers the appropriate data and delivers it to the user in a single, combined package. It also provides analytics, protection against threats and other security for the application.

The primary role of an API Gateway is to act as a single entry point and standardized process for interactions between an organization’s apps, data and services and internal and external customers.

and for have a single entry point to our microservices, we have to create new service spring-boot called gatway-api and add the configuration to register it in the discovery euroka.
For the configuration to blance between service back-end I add the configuration in application.yml file for api-gateway

  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
      routes:
        - id: customer
          uri: lb://CUSTOMER-SERVICE
          predicates:
            - Path=/api/customers/**
          filters:
            - TokenRelay=
        - id: invoice
          uri: lb://INVOICE-SERVICE
          predicates:
            - Path=/api/invoices/**
          filters:
            - TokenRelay=
Enter fullscreen mode Exit fullscreen mode

in the configuration I use the name of services as uri and this example also demonstrates the Spring Cloud Netflix Ribbon load-balancing (defined by the lb prefix on the destination URI)

Authentification

After complete our application and test all the functionallity, we have to secure our ressources by using spring security, in this app I use Oauth2 protocol with Keycloak as ressource server for manage the users of the client and thier authorization

Manage Microservices with Docker Compose

Docker-compose is an orchestration tool that manages containerized applications. For our project, this means we have two high-level steps to get managed microservice containers
- 1. containerize our currently-local applications,
- 2. set up the management layer with Docker Compose.

Docker file

Each service has own docker file for build the image .
example

 FROM maven:3-openjdk-11  as builder
WORKDIR /customer
COPY pom.xml pom.xml
COPY src src
RUN mvn clean package

FROM openjdk:11
COPY --from=builder /customer/target/customer-1.0-SNAPSHOT.jar customer.jar
EXPOSE 8089
CMD ["java", "-jar", "customer.jar"]
Enter fullscreen mode Exit fullscreen mode

docker compose

After create Docker file for each service, We need to create a YAML file with container details, configuration, and commands we want Compose to execute.
At the high level, we will list each of our services, then specify subfields for each. We will also set up a dedicated network for all of the containers to run on, so that way we create app.yml file under docker folder that contains all services of the application and we add new service zipkin for trace all HTTP request.

Schema of the project

architecture

links:

github rep
microservice blog
Api gateway

Top comments (0)