**Microservices with Spring Boot**
Tags: spring, keycloak, microservices, cloud
Published: 2022-09-26 17:14:47

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mdu1dx2xpwxbrv7jni2e.png)
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](https://spring.io/projects/spring-cloud-openfeign) that create a dynamic implementation of an interface decorated with JAX-RS or Spring MVC annotation.

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

  @GetMapping("api/customers")
  List<Customer> getCustomers();
}
```

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

```xml
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
```

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

```java
@SpringBootApplication
@EnableFeignClients
public class InvoiceApplication {
  public static void main(String[] args) {
    SpringApplication.run(InvoiceApplication.class, args);
  }
}
```

## Applications - Service 1

Customers service created to manage customers of our application, and for that we create a spring boot application using [spring initializer](https://start.spring.io/), with H2 database with spring Data for manage persist data and spring web for create the end points.

```xml
    <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>
```

and finally we have the service Cutomers

![customer project](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/f8codqpvz7fkaznw1q9p.png)

we have to add some configuration propertie to application.yml in ressource folder
```yml
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
```

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.

```java
@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);
    };
  }
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g3qqp9ytio7huhyuexdu.png)

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.
```java
@Getter
@Setter
@ToString
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
  private Integer id;
  private String firstName;
  private String lastName;
  private String email;
}
```

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 
 ```xml
 	<dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
      </dependency>
```

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

```java
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
  public static void main(String[] args) {
    SpringApplication.run(EurekaServerApplication.class, args);
  }
}
```
Now we need to define some properties to application.properties file.
```yml
spring:
  application:
    name: eureka-server
server:
  port: 8761
eureka:
  client:
    fetch-registry: false
    register-with-eureka: false
```

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
```yml
	eureka:
    client:
      service-url:
        defaultZone: http://localhost:8761/eureka
      fetch-registry: true
      register-with-eureka: true
```

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
```yml
  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=
```

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 
 ```dockerfile
 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"]
```

### 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/065bdbjiunqq69742wp7.png)
### links:
[github rep](https://github.com/Abdelouahedd/microservice-demo) 
[microservice blog](https://jmhreif.com/blog/microservices-level5/)
[Api gateway](https://medium.com/buildpiper/how-do-api-gateways-work-3b989fdcd751)