Hello! Welcome to the next stage of building our microservices architecture.
In the previous lessons, we successfully set up a service registry with Eureka and an API Gateway to route external requests. Now, our services exist, but they are mostly isolated islands. A true microservice system requires services to collaborate and communicate with each other.
This lesson focuses on exactly that, addressing the learning outcome: Implement synchronous inter-service communication using RestTemplate or Feign. We will explore how one service can make a direct, blocking call to another to request data or trigger an action.
By the end of this ~60-minute lesson, you will understand:
- The concept of synchronous inter-service communication.
- How to implement service-to-service calls using the traditional
RestTemplate. - How to simplify this communication dramatically using the modern, declarative
Feign Client. - The key differences and trade-offs between these two approaches.
Let's enable our services to talk to one another.
Synchronous vs. Asynchronous Communication
In a microservices architecture, services can communicate in two primary ways: synchronously or asynchronously.
- Synchronous: Service A sends a request to Service B and waits for a response. It is blocked until Service B completes the operation and replies. This is like making a phone call and waiting for the other person to answer and give you the information you need. RESTful API calls over HTTP are a classic example of synchronous communication.
- Asynchronous: Service A sends a message to a message broker (like RabbitMQ or Kafka) and continues its work without waiting for a response. Service B (and any other interested services) will eventually pick up and process that message. This is like sending an email; you don't wait for an immediate reply.
Today, we are focusing on the synchronous pattern, which is very common for queries or commands that require an immediate result.
Approach 1: The Traditional Way with RestTemplate
RestTemplate has been the standard synchronous HTTP client in Spring for many years. It is an imperative client, meaning you have to manually build the request, execute it, and handle the response.
Let's imagine our service-b needs to get data from service-a. With RestTemplate, the code in service-b might look something like this:
- Configure a
RestTemplateBean: You first need aRestTemplateinstance, often configured as a bean with load balancing capabilities. - Manually Build the URL: You construct the URL string, using the service name from Eureka (e.g.,
http://service-a/endpoint). - Execute the Request: You call methods like
getForObject()or the more powerfulexchange(). - Handle Serialization: You often need to specify the expected response type for proper deserialization from JSON to your Java object.
This process involves a significant amount of "boilerplate" code that is repeated for every call.
Microservice Communication Made Easy ! Feign Client in Spring Boot 🔥 @Javatechie
To see what this boilerplate looks like in practice, watch this segment from the video 'Microservice Communication Made Easy ! Feign Client in Spring Boot' by Java Techie. It demonstrates a typical call using RestTemplate.
Watch from 03:25 to 05:00. Notice the manual URL building and the need to specify the return type for deserialization. This highlights the verbosity of the RestTemplate approach.
While functional, RestTemplate is now in maintenance mode in Spring. For new projects, there's a much cleaner alternative.
Approach 2: The Modern Way with Spring Cloud OpenFeign
Spring Cloud OpenFeign is a declarative REST client. "Declarative" means you simply declare what you want to do, and the framework handles the implementation. Instead of writing the code to build an HTTP request, you define a Java interface and annotate its methods. Spring then generates a class that implements this interface for you at runtime.
This approach dramatically reduces boilerplate and makes your code cleaner and more readable.
Implementing a Feign Client: Step-by-Step
Let's turn service-b into a Feign client that can call service-a.
1. Add the Dependency
First, add the OpenFeign starter to service-b's pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
Remember to also have the spring-cloud-dependencies in your dependencyManagement section, which you should already have from setting up Eureka and the Gateway.
2. Enable Feign Clients
In your main application class for service-b, add the @EnableFeignClients annotation.
package com.example.serviceb;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients // This annotation scans for Feign client interfaces
public class ServiceBApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceBApplication.class, args);
}
}
3. Define the Feign Client Interface
This is the core of Feign. Create a new Java interface in service-b. This interface will act as a proxy for service-a's REST API.
Let's assume service-a has a controller with this endpoint:@GetMapping("/hello") which returns a String.
Your Feign client interface in service-b would look like this:
package com.example.serviceb.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
@FeignClient(name = "service-a") // The Eureka service ID of the service to call
public interface ServiceAClient {
@GetMapping("/hello") // This must match the endpoint signature in service-a
String sayHello();
}
Key points about the @FeignClient annotation:
name = "service-a": This is the crucial part. You provide the service ID of the target microservice as registered in Eureka. Spring Cloud's load balancer will use this name to look up an available instance ofservice-aand send the request there. You don't need to hardcode any hostnames or ports.- The method signatures inside the interface (
sayHello()) and their annotations (@GetMapping("/hello")) must match the REST endpoints exposed by the target service'sRestController.
4. Inject and Use the Client
Now, you can inject and use this client in any of service-b's components (like a service or controller) just like any other Spring bean.
package com.example.serviceb.controller;
import com.example.serviceb.client.ServiceAClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ServiceBController {
private final ServiceAClient serviceAClient;
@Autowired
public ServiceBController(ServiceAClient serviceAClient) {
this.serviceAClient = serviceAClient;
}
@GetMapping("/call-a")
public String callServiceA() {
// Just call the interface method! No RestTemplate, no URL building.
String responseFromA = serviceAClient.sayHello();
return "Service B received: '" + responseFromA + "'";
}
}
Notice how clean this is. The call serviceAClient.sayHello() looks like a simple local method call, but behind the scenes, Feign is creating and sending an HTTP request to service-a and deserializing the response.
Microservice Communication Made Easy ! Feign Client in Spring Boot 🔥 @Javatechie
The 'Java Techie' video provides a full, hands-on demonstration of this entire process. Watching it will solidify your understanding.
Watch from 05:35 to 16:19. This covers defining the Feign client interface, injecting and using it, enabling Feign, and testing the end-to-end communication via Swagger. This is the core practical part of the lesson.
Test your understanding!
Imagine the service-a application exposes another endpoint to retrieve a user by their ID:
// In Service A's UserController
@GetMapping("/users/{id}")
public User getUserById(@PathVariable("id") Long userId) {
// ... logic to find and return a user
}
How would you define the corresponding method in your ServiceAClient Feign interface in service-b? Assume a User DTO class is available in service-b.
Show answer
You would add a method to the ServiceAClient interface that perfectly mirrors the controller's method signature, including the @PathVariable annotation.
// In ServiceB's ServiceAClient interface
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
// ... other imports
public interface ServiceAClient {
@GetMapping("/hello")
String sayHello();
// New method for fetching a user
@GetMapping("/users/{id}")
User getUserById(@PathVariable("id") Long userId);
}
Now, calling serviceAClient.getUserById(123L) in service-b would make a GET request to http://service-a/users/123.
Comparing Your Options: Feign vs. RestTemplate
Now that you've seen both approaches, let's summarize the differences.

Calling REST Services in Spring Boot: Complete CRUD ...
For a detailed, code-driven comparison showing full CRUD (Create, Read, Update, Delete) operations with both Feign and RestTemplate, the following article is an excellent resource.
Skim through the sections 'Approach 1 – Using Spring Cloud OpenFeign' and 'Using RestTemplate - Full CRUD' to see the difference in code volume and complexity. Then, carefully read the 'Comparison Table' and 'Conclusion' sections at the end for a final summary and best-practice recommendations.
The verdict is clear: For new microservice projects built with Spring Cloud, Spring Cloud OpenFeign is the recommended choice for synchronous communication. It leads to more maintainable, readable, and less error-prone code.
Conclusion
Great job! You have now mastered a fundamental pattern for building distributed systems: synchronous inter-service communication. You can now make your microservices collaborate effectively to perform complex business operations.
Key Takeaways:
- Synchronous communication is a request/response pattern where the client waits for the server's reply.
RestTemplateis the traditional, imperative way to make HTTP calls in Spring, but it involves significant boilerplate code.- Spring Cloud OpenFeign is a modern, declarative client that simplifies communication by letting you define an interface with annotations.
- Feign integrates seamlessly with service discovery (Eureka) and client-side load balancing, making it ideal for microservice architectures.
What's Next?
Our services can now call each other, but this introduces a new point of failure. What happens if service-a is slow or goes down? The call from service-b will hang and eventually time out, potentially causing a chain reaction of failures that could bring down your entire system. This is known as a cascading failure.
In our next lesson, we will tackle this problem head-on by implementing the Circuit Breaker pattern using Resilience4j. You'll learn how to make your services resilient to failures in their dependencies, which is a critical step toward building robust, production-grade applications.