Open In App

Spring Boot Microservices – Load Balancing using Netflix’s Ribbon

Last Updated : 21 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Microservices are small, loosely coupled distributed services. Microservices architecture evolved as a solution to the scalability, independently deployable, and innovation challenges with Monolithic Architecture. It provides us to take a big application and break it into efficiently manageable small components with some specified responsibilities. It is considered the building block of modern applications.

Taking about the general definition, Load Balancer is a network device that sits between a set of backend servers and clients. It distributes the incoming traffic to multiple servers to reduce the load. Load Balancers typically use various algorithms, such as round-robin to determine which server to send incoming traffic to. In Spring, if you want to use Load Balancer then Spring Cloud provides us with some already developed ready-made Load Balancer. By using this you don’t need to write any Load Balancer or create your own, you can just use the tool very easily by importing some dependencies and writing minimal code.

Note: Please refer to this article Spring Cloud – Load Balancer

Ribbon is a particular load balancer given by Netflix you don’t have to write any code to develop this load balancer or to make this pattern happens. We can simply use the Netflix Ribbon to have the client-side load balancing. So, in this article, we are going to see how Netflix’s Ribbon helping us with client-side load balancing in Spring Boot Microservices.

How to Use Netflix’s Ribbon in Spring Boot Microservices?

Add the following dependency in your pom.xml file

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Annotate your Feign Client interface with @RibbonClient. Refer to the below code snippet.

@FeignClient(name = "address-service", path = "/address-service")
@RibbonClient(name = "address-service")
public interface AddressClient {

@GetMapping("/address/{id}")
public ResponseEntity<AddressResponse> getAddressByEmployeeId(@PathVariable("id") int id);

}

Make the following changes in your application.properties file.

address-service.ribbon.listOfServers=http://localhost:8081, http://localhost:8082

Let’s understand the whole thing by developing two Spring Boot Microservices.

Example Microservices

In this project, we are going to develop two Microservices

  1. employee-service
  2. address-service

Developing employee-service Step by Step

Step 1: Create a New Spring Boot Project in Spring Initializr

To create a new Spring Boot project, please refer to How to Create a Spring Boot Project in Spring Initializr and Run it in IntelliJ IDEA. For this project choose the following things

  • Project: Maven
  • Language: Java
  • Packaging: Jar
  • Java: 17

 Please choose the following dependencies while creating the project.

  • Spring Boot DevTools
  • Spring Data JPA
  • MySQL Driver
  • Spring Web
  • OpenFeign

Generate the project and run it in IntelliJ IDEA by referring to the above article.

Note: We have used the MySQL database in this project.

Step 2: Add Ribbon Dependency from Maven Central

Add the following dependency in your pom.xml file

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Step 3: Create Schema in MySQL Workbench and Put Some Sample Data

Go to your MySQL Workbench and create a schema named gfgmicroservicesdemo and inside that create a table called employee and put some sample data as shown in the below image. Here we have created 4 columns and put some sample data.

  1. id
  2. name
  3. email
  4. age

Spring-Boot-Microservices-1

Now we are going to fetch Employee Data from Employee Table in our Spring Boot project. To do it refer to the following steps. Before moving to IntelliJ IDEA let’s look at the complete project structure for our Microservices.

Feignclient-1

Step 4: Make Changes in Your application.properties File

Now make the following changes in your application.properties file.

spring.datasource.url=jdbc:mysql://localhost:3306/gfgmicroservicesdemo
spring.datasource.username=put your username here
spring.datasource.password=put your password here

spring.application.name=employee-service
server.port=8080

# Set Your Context Path Here
server.servlet.context-path=/employee-service

address-service.ribbon.listOfServers=http://localhost:8081, http://localhost:8082

Step 5: Create Your Entity/Model Class

Go to the src > main > java > entity and create a class Employee and put the below code. This is our model class.

Java




package com.gfg.employeaap.entity;
 
import jakarta.persistence.*;
 
@Entity
@Table(name = "employee")
public class Employee {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
 
    @Column(name = "name")
    private String name;
 
    @Column(name = "email")
    private String email;
 
    @Column(name = "age")
    private String age;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public String getAge() {
        return age;
    }
 
    public void setAge(String age) {
        this.age = age;
    }
}


Step 6: Create Your Repository Interface

Go to the src > main > java > repository and create an interface EmployeeRepo and put the below code. This is our repository where we write code for all the database-related stuff.

Java




package com.gfg.employeaap.repository;
 
import com.gfg.employeaap.entity.Employee;
import org.springframework.data.jpa.repository.JpaRepository;
 
@Repository
public interface EmployeeRepo extends JpaRepository<Employee, Integer> {
 
}


Note: Please refer to this article to know more about JpaRepository.

Step 7: Create an EmployeeResponse and AddressResponse Class

Go to the employee-service > src > main > java > response and create a class AddressResponse and put the below code.

Java




package com.gfg.employeaap.response;
 
public class AddressResponse {
 
    private int id;
    private String city;
    private String state;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
}


Go to the src > main > java > response and create a class EmployeeResponse and put the below code.

Java




package com.gfg.employeaap.response;
 
public class EmployeeResponse {
 
    private int id;
    private String name;
    private String email;
    private String age;
   
    // Add AddressResponse Here
    private AddressResponse addressResponse;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public String getAge() {
        return age;
    }
 
    public void setAge(String age) {
        this.age = age;
    }
 
    public AddressResponse getAddressResponse() {
        return addressResponse;
    }
 
    public void setAddressResponse(AddressResponse addressResponse) {
        this.addressResponse = addressResponse;
    }
}


Step 8: Create an AddressClient Interface

Go to the employee-service > src > main > java > feignclient and create an interface AddressClient and put the below code.

Java




package com.gfg.employeaap.feignclient;
 
import com.gfg.employeaap.response.AddressResponse;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
 
@FeignClient(name = "address-service", path = "/address-service")
@RibbonClient(name = "address-service")
public interface AddressClient {
 
    @GetMapping("/address/{id}")
    public ResponseEntity<AddressResponse> getAddressByEmployeeId(@PathVariable("id") int id);
 
}


Step 9: Modify EmployeeServiceApplication Class

Go to the employee-service > src > main > java > EmployeeServiceApplication and annotate it with @EnableFeignClients annotation. Below is the complete code for EmployeeServiceApplication Class.

Java




package com.gfg.employeaap;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
@SpringBootApplication
@EnableFeignClients
public class EmployeeServiceApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(EmployeeServiceApplication.class, args);
    }
 
}


Step 10: Create Your Service Class

Now go to the employee-service > src > main > java > service > EmployeeService and below is the complete code for EmployeeService Class.

Java




package com.gfg.employeaap.service;
 
import com.gfg.employeaap.entity.Employee;
import com.gfg.employeaap.feignclient.AddressClient;
import com.gfg.employeaap.repository.EmployeeRepo;
import com.gfg.employeaap.response.AddressResponse;
import com.gfg.employeaap.response.EmployeeResponse;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
 
import java.util.Optional;
 
@Service
public class EmployeeService {
 
    @Autowired
    private EmployeeRepo employeeRepo;
 
    @Autowired
    private ModelMapper mapper;
 
    // Spring will create the implementation
    // for this class
    // and will inject the bean here (proxy)
    @Autowired
    private AddressClient addressClient;
 
    public EmployeeResponse getEmployeeById(int id) {
 
        Optional<Employee> employee = employeeRepo.findById(id);
        EmployeeResponse employeeResponse = mapper.map(employee, EmployeeResponse.class);
 
        // Using FeignClient
        ResponseEntity<AddressResponse> addressResponse = addressClient.getAddressByEmployeeId(id);
        employeeResponse.setAddressResponse(addressResponse.getBody());
 
        return employeeResponse;
    }
 
}


Step 11: Create an Employee Controller

Go to the src > main > java > controller and create a class EmployeeController and put the below code. Here we are going to create an endpoint “/employees/{id}” to find an employee using id.

Java




package com.gfg.employeaap.controller;
 
import com.gfg.employeaap.response.EmployeeResponse;
import com.gfg.employeaap.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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;
 
@RestController
public class EmployeeController {
 
    @Autowired
    private EmployeeService employeeService;
 
    @GetMapping("/employees/{id}")
    private ResponseEntity<EmployeeResponse> getEmployeeDetails(@PathVariable("id") int id) {
        EmployeeResponse employee = employeeService.getEmployeeById(id);
        return ResponseEntity.status(HttpStatus.OK).body(employee);
    }
 
}


Step 12: Create a Configuration Class

Go to the src > main > java > configuration and create a class EmployeeConfig and put the below code.

Java




package com.gfg.employeaap.configuration;
 
import com.gfg.employeaap.service.EmployeeService;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class EmployeeConfig {
 
    @Bean
    public ModelMapper modelMapperBean() {
        return new ModelMapper();
    }
 
}


Note: You may refer to these two articles

Before running the Microservice below is the complete pom.xml file. Please cross-verify if you have missed some dependencies.

Important: If you are getting errors please compare your pom.xml file with the below pom.xml file and make changes if you have missed something.

XML




<?xml version="1.0" encoding="UTF-8"?>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg.employeaap</groupId>
    <artifactId>employee-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>employee-service</name>
    <description>Employee Service</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR5</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.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>3.1.1</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </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>
            </plugin>
        </plugins>
    </build>
 
</project>


Developing address-service Step by Step

Step 1: Create a New Spring Boot Project in Spring Initializr

To create a new Spring Boot project, please refer to How to Create a Spring Boot Project in Spring Initializr and Run it in IntelliJ IDEA. For this project choose the following things

  • Project: Maven
  • Language: Java
  • Packaging: Jar
  • Java: 17

 Please choose the following dependencies while creating the project.

  • Spring Boot DevTools
  • Spring Data JPA
  • MySQL Driver
  • Spring Web

Generate the project and run it in IntelliJ IDEA by referring to the above article.

Note: We have used the MySQL database in this project.

Step 2: Create Schema in MySQL Workbench and Put Some Sample Data

Go to your MySQL Workbench and create a schema named gfgmicroservicesdemo and inside that create a table called address and put some sample data as shown in the below image. 

Address Table:

Here we have created 4 columns and put some sample data.

  1. id
  2. city
  3. state
  4. employee_id

Note: In the Address table, employee_id is a foreign key so create it accordingly. We are going to perform a SQL join operation in our native SQL query. So create tables carefully.

Spring-Boot-Native-Query-1

Before moving to IntelliJ IDEA let’s have a look at the complete project structure for our Microservices.

Spring-Boot-Native-Query-2

Step 3: Make Changes in Your application.properties File

Now make the following changes in your application.properties file.

spring.datasource.url=jdbc:mysql://localhost:3306/gfgmicroservicesdemo
spring.datasource.username=put your username here
spring.datasource.password=put your password here

spring.application.name=address-service
server.port=8081
server.servlet.context-path=/address-service

Step 4: Create Your Entity/Model Class

Go to the src > main > java > entity and create a class Address and put the below code. This is our model class.

Java




package com.gfg.addressapp.entity;
 
import jakarta.persistence.*;
 
@Entity
@Table(name = "address")
public class Address {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;
 
    @Column(name = "city")
    private String city;
 
    @Column(name = "state")
    private String state;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
}


Step 5: Create Your Repository Interface

Go to the src > main > java > repository and create an interface AddressRepo and put the below code. This is our repository where we write code for all the database-related stuff.

Java




package com.gfg.addressapp.repository;
 
import com.gfg.addressapp.entity.Address;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
 
@Repository
public interface AddressRepo extends JpaRepository<Address, Integer> {
 
    @Query(
        nativeQuery = true,
        value
        = "SELECT ea.id, ea.city, ea.state FROM gfgmicroservicesdemo.address ea join gfgmicroservicesdemo.employee e on e.id = ea.employee_id where ea.employee_id=:employeeId")
       Optional<Address> findAddressByEmployeeId(@Param("employeeId") int employeeId);
}


Note: Please refer to this article to know more about JpaRepository.

Step 6: Create an AddressResponse Class

Go to the src > main > java > response and create a class AddressResponse and put the below code.

Java




package com.gfg.addressapp.response;
 
public class AddressResponse {
 
    private int id;
    private String city;
    private String state;
 
    public int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getCity() {
        return city;
    }
 
    public void setCity(String city) {
        this.city = city;
    }
 
    public String getState() {
        return state;
    }
 
    public void setState(String state) {
        this.state = state;
    }
}


Step 7: Create Your Service Class

Go to the src > main > java > service and create a class AddressService and put the below code. This is our service class where we write our business logic.

Java




package com.gfg.addressapp.service;
 
import com.gfg.addressapp.entity.Address;
import com.gfg.addressapp.repository.AddressRepo;
import com.gfg.addressapp.response.AddressResponse;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import java.util.Optional;
 
@Service
public class AddressService {
 
    @Autowired
    private AddressRepo addressRepo;
 
    @Autowired
    private ModelMapper mapper;
 
    public AddressResponse findAddressByEmployeeId(int employeeId) {
        Optional<Address> addressByEmployeeId = addressRepo.findAddressByEmployeeId(employeeId);
        AddressResponse addressResponse = mapper.map(addressByEmployeeId, AddressResponse.class);
        return addressResponse;
    }
 
}


Step 8: Create an Address Controller

Go to the src > main > java > controller and create a class AddressController and put the below code. Here we are going to create an endpoint “/address/{employeeId}” to find the address using employee_id. Thats why we have created a foreign key in the Address table and we have performed the SQL join operation in the native query to get our desired result.

Java




package com.gfg.addressapp.controller;
 
import com.gfg.addressapp.response.AddressResponse;
import com.gfg.addressapp.service.AddressService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
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;
 
@RestController
public class AddressController {
 
    @Autowired
    private AddressService addressService;
 
    @GetMapping("/address/{employeeId}")
    public ResponseEntity<AddressResponse> getAddressByEmployeeId(@PathVariable("employeeId") int employeeId) {
        AddressResponse addressResponse = addressService.findAddressByEmployeeId(employeeId);
        return ResponseEntity.status(HttpStatus.OK).body(addressResponse);
    }
 
}


Step 9: Create a Configuration Class

Go to the src > main > java > configuration and create a class AddressConfig and put the below code.

Java




package com.gfg.addressapp.configuration;
 
import com.gfg.addressapp.service.AddressService;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class AddressConfig {
 
    @Bean
    public ModelMapper modelMapperBean() {
        return new ModelMapper();
    }
 
}


Note: You may refer to these two articles

Before running the Microservice below is the complete pom.xml file. Please cross-verify if you have missed some dependencies

XML




<?xml version="1.0" encoding="UTF-8"?>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.gfg.addressapp</groupId>
    <artifactId>address-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>address-service</name>
    <description>Address Service</description>
    <properties>
        <java.version>17</java.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.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>3.1.1</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>


Run Both Your Address and Employee Microservices

Now run your both Address and Employee Microservices. If everything goes well then you may see the following screen in your console. Please refer to the below image.

microservice-communication-2

Step 7: Test Your Endpoint in Postman

Now open Postman and hit the following URL

GET: http://localhost:8080/employee-service/employees/2

And you can see the following response

{
"id": 2,
"name": "Asish",
"email": "asis@gmail",
"age": "30",
"addressResponse": {
"id": 1,
"city": "BLS",
"state": "Odisha"
}
}

Please refer to the below image.

microservice-communication-3



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads