Implementation of Spring WebClient Load Balancing

Create the EurekaServer Service

Step 1: Create a spring boot project using Spring Initializr, and add the below dependencies:

Dependencies:

  • Spring Web
  • Eureka Server
  • Spring Dev Tools
  • Lombok

After creating the project, the folder structure will be like below image:

Step 2: Open application.properties and write the below properties to configure the server port and Eureka server configurations.

spring.application.name=EurekaServerService
server.port=8761
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.client.service-url.defaultZone =http://${eureka.instance.hostname}:${server.port}/eureka


Step 3: In the main class, include @EnableEurekaServer annotation to activate the Eureka server functionality of the application.

Java
package org.example.eurekaserverservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerServiceApplication {

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

}


Step 4: Run the application

Once the project is completed, run the application and it will start at port 8761.

Create the example-service

Step 1: Create a spring boot project using spring initializer and add the below dependencies.

Dependencies:

  • Spring Web
  • Spring Dev Tools
  • Lombok

After creating the project, the folder structure will be like below.


Step 2: Open application.properties and write the below properties to configure the server port and Eureka server configurations.

spring.application.name=example-service


server.port=8082
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true

spring.cloud.loadbalancer.ribbon.enabled=false


Step 3: Create the ServiceController class

Go to src > main > java > org.example.exampleservice > ServiceController and put the below code.

Java
package org.example.exampleservice;



import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ServiceController {

    @GetMapping("/test")
    public String test() {
        return "Hello from your-service instance!";
    }
}


Step 4: In the main class, include @EnableDiscoveryClient annotation to activate the Eureka client functionality of the application.

Java
package org.example.exampleservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ExampleServiceApplication {

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

}


pom.xml:

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>3.2.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>example-service</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>example-service</name>
    <description>example-service</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.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-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </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>
            </plugin>
        </plugins>
    </build>

</project>


Step 5: Run the application

Once the project is completed, run the application and it will start at port 8082.


Create the WebClient

Step 1: Create a Spring project using Spring Initializr, and add the below dependencies:

Dependencies:

  • Spring Web
  • Eureka Server
  • Spring Dev Tools
  • Lombok

After successfully the project creation done, the folder structure will be like below.


Step 2: Open the application.properties and write the below properties to configure server port and Eureka server configurations.

spring.application.name=web-client

spring.cloud.loadbalancer.ribbon.enabled=false

eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.instance.hostname=localhost
eureka.client.register-with-eureka=true
eureka.client.fetch-registry=true


Step 3: Create the WebClientConfig class

Go to src > main > java > org.example.webclient > config > WebClientConfig and put the below code.

Java
package org.example.webclient.config;



import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.function.client.WebClient;

@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}


Step 4: Create the TestController class

Go to src > main > java > org.example.webclient > controller > TestController and put the below code.

Java
package org.example.webclient.controller;



import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import org.springframework.http.HttpStatus;

import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Mono;

@RestController
public class TestController {

    @Autowired
    private WebClient.Builder webClientBuilder;

    @GetMapping("/test")
    public Mono<String> testLoadBalancer() {
        return webClientBuilder.build()
                .get()
                .uri("http://example-service/test")
                .retrieve()
                .bodyToMono(String.class)
                .onErrorResume(WebClientResponseException.class, ex -> {
                    if (ex.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
                        return Mono.just("Internal Server Error: " + ex.getMessage());
                    } else {
                        return Mono.error(ex);
                    }
                })
                .onErrorResume(Exception.class, ex -> Mono.just("An unexpected error occurred: " + ex.getMessage()));
    }
}


Step 5: In the main class, include @EnableDiscoveryClient annotation to activate the Eureka client functionality of the application.

Java
package org.example.webclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class WebClientApplication {

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

}


pom.xml:

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>3.2.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>org.example</groupId>
    <artifactId>web-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>web-client</name>
    <description>web-client</description>
    <properties>
        <java.version>17</java.version>
        <spring-cloud.version>2023.0.1</spring-cloud.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-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-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>
            </plugin>
        </plugins>
    </build>

</project>


Step 6: Run the application

Once the project is completed, run the application and it will start at port 8080.


EurekaServer Dashboard

http://localhost:8761

Output:


WebClient Testing

GET http://localhost:8080/test

Output:

Spring WebClient Load Balancing

Spring WebClient is a non-blocking and it is a reactive client for making HTTP requests. When building the microservices, it is essential to distribute requests evenly across the service instance to ensure scalability and reliability. Spring Cloud LoadBalancer can provide an easy way to integrate load balancing with WebClient. It allows us to distribute the requests among multiple of the services registered with the service discovery tool like Eureka.

Load Balancing in Microservices

In the microservices architecture, load balancing helps to distribute the incoming network traffic across multiple servers or service instances. It can ensure no single instance is overwhelmed and improve reliability. Spring Cloud LoadBalancer, when used with WebClient, allows the automatic distribution of the requests among service instances.

Working of Spring Cloud LoadBalancer

Spring Cloud LoadBalancer can use different algorithms to balance the requests. When the request is made using the WebClient the LoadBalancer intercepts it and redirects it to the appropriate service instance of the application.

Similar Reads

Implementation of Spring WebClient Load Balancing

Create the EurekaServer Service...

Contact Us