Spring Boot Microservice Communication: What's New?

Yash SaxenaYash Saxena
4 min read

Spring Boot has long been favored for its ability to simplify the bootstrapping and development of new Spring applications. Part of this simplification is the abstraction of complex configurations and operations behind concise, intention-revealing interfaces. One such feature is the Feign client, which provides a declarative way of writing HTTP clients. However, with the rise of non-blocking and reactive programming, there’s been a shift towards using Web Client.

The Need for Transition

Feign Client, while powerful and easy to use, operates on a blocking I/O model. This means that the thread making the HTTP request is blocked until the response is returned. In contrast, WebClient is part of Spring WebFlux, which supports non-blocking I/O and allows for reactive programming. This transition aligns with the industry’s move towards building more scalable and efficient microservices.

Advantages of Web Client

  • Non-blocking Operations: Allows other tasks to proceed without waiting for the HTTP response.

  • Reactive Streams: Integration with reactive streams allows for backpressure and more efficient resource usage.

  • Functional Style: WebClient supports a more functional style of programming which can lead to cleaner code.

Disadvantages of WebClient

  • Learning Curve: Developers familiar with Feign may need time to adapt to the functional programming model.

  • Complexity: For simple use-cases, WebClient can seem more complex compared to the straightforward annotations of Feign.

Here’s how you can use Web Client in Spring Boot:

import org.springframework.web.reactive.function.client.WebClient;

@Service
public class ProductService {

private final WebClient webClient;

public ProductService(WebClient.Builder webClientBuilder) {
this.webClient = webClientBuilder.baseUrl("http://product-service").build();
}
publicMono<Product> getProduct(String id) {
    return webClient.get()
            .uri("/products/{id}", id)
            .headers((headers) -> headers.add("authorization", "Bearer " + token))
            .retrieve()
            .bodyToMono(Product.class)
            .block();
    }
}

Error Handling made easy with Web Client

  • Handle error based on Status code

      import org.springframework.web.reactive.function.client.WebClient;
    
      @Service
      public class ProductService {
    
      private final WebClient webClient;
    
      public ProductService(WebClient.Builder webClientBuilder) {
      this.webClient = webClientBuilder.baseUrl("http://product-service").build();
      }
      publicMono<Product> getProduct(String id) {
          return webClient.get()
                  .uri("/products/{id}", id)
                  .headers((headers) -> headers.add("authorization", "Bearer " + token))
                  .retrieve()
                  .onStatus(httpStatus -> httpStatus.value() == <desired Status code>,
                      error -> Mono.error(new UserDefinedException("error Body")))
                  .bodyToMono(Product.class)
                  .block();
          }
      }
    
  • Based on error do some retries and when retries are exhausted throw some specific exception

      import org.springframework.web.reactive.function.client.WebClient;
    
      @Service
      public class ProductService {
    
      private final WebClient webClient;
    
      public ProductService(WebClient.Builder webClientBuilder) {
      this.webClient = webClientBuilder.baseUrl("http://product-service").build();
      }
      publicMono<Product> getProduct(String id) {
          return webClient.get()
                  .uri("/products/{id}", id)
                  .headers((headers) -> headers.add("authorization", "Bearer " + token))
                  .retrieve()
                  .bodyToMono(Product.class)
                  .onErrorResume(Mono::error)
                  .retryWhen(Retry.backoff(3, Duration.of(2, ChronoUnit.SECONDS))
                  .onRetryExhaustedThrow((retryBackoffSpec, retrySignal) ->
                          new UserCustomException(retrySignal.failure())))
                  .block();
                  }catch(UserCustomException userCustomException){
                      //Error Handling logic
                  }
      }
    

The above mentioned code snippet shows how to achieve exponential retry using webclient. “Retry.backoff(3, Duration.of(2, ChronoUnit.SECONDS)” , this line encapsulates the needed logic for retry.

  • 3 denotes the maximum number of retries that are to be executed before implementing the exhaustion logic

  • 2 seconds denotes the minimum time before the first backoff kicks in.

Once the retries are exhausted onRetryExhaustedThrow() gets executed and thus we can handle the error as per our business logic.

Industry Trend

The industry trend shows a gradual shift towards non-blocking architectures. Major cloud providers and high-traffic services are adopting reactive streams and non-blocking I/O to handle massive scale and efficiency.

In conclusion, while Feign Client has served us well, the transition to WebClient represents an evolution in line with modern software architecture trends. It offers scalability, efficiency, and a more responsive system design that is becoming increasingly important in today’s fast-paced digital landscape.

Considering RestTemplate as an Alternative

Before WebClient, another popular choice for making HTTP requests in Spring Boot was RestTemplate. It’s a synchronous, blocking client that has been part of Spring Framework for a long time.

Should We Still Use RestTemplate?

RestTemplate is simpler and may still be suitable for applications that don’t require the scalability provided by non-blocking I/O. However, it’s important to note that as of Spring Framework 5, RestTemplate has been in maintenance mode, with the Spring team recommending WebClient for new developments.

Transitioning to WebClient

Ultimately, the decision to transition from RestTemplate to WebClient should be based on the specific needs of your application. If you’re building a high-throughput, reactive system, or if you’re already using Spring WebFlux, then WebClient is the way forward. For legacy systems or applications where the non-blocking model doesn’t bring significant benefits, RestTemplate can still be a valid choice.

Here’s a quick comparison:

  • RestTemplate: Synchronous and blocking. Simpler for basic use-cases but not recommended for new developments.

  • WebClient: Asynchronous and non-blocking. Supports reactive programming and is recommended for modern, scalable applications.

In summary, while RestTemplate is still functional, the industry is moving towards WebClient and reactive programming to meet the demands of modern software systems. The transition should be considered an investment in your application’s future scalability and responsiveness.

Thanks for reading...

Do checkout previous posts and blogs:

0
Subscribe to my newsletter

Read articles from Yash Saxena directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Yash Saxena
Yash Saxena