Spring Boot Microservices with Eureka and Feign

Microservices architecture allows developers to build modular, scalable, and loosely coupled applications. When working with microservices, Eureka and Feign are powerful tools that simplify service discovery and inter-service communication. Eureka, part of the Netflix OSS stack, serves as a service registry, while Feign provides declarative HTTP client support for easy communication between microservices. Together, they enable dynamic service discovery and seamless interaction between services.

This guide provides a step-by-step tutorial to set up a microservices architecture using Spring Boot, Eureka, and Feign. It covers the essentials of setting up a Eureka server and clients, registering services, handling inter-service communication with Feign, and leveraging Ribbon for load balancing.

Table of Contents

  1. Setting up Eureka Server and Clients
  2. Registering Services
  3. Using Feign for Inter-Service Calls
  4. Load Balancing with Ribbon
  5. External Resources for Further Learning
  6. Final Thoughts

Setting up Eureka Server and Clients

What is Eureka?

Eureka is a service registry that stores information about all registered services, including their locations (hostnames/IPs) and ports. This information enables microservices to discover and interact with each other dynamically, without hardcoding service URLs.

Adding Dependencies

Eureka Server

Add the following dependencies to your pom.xml:

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

Eureka Client

For services acting as Eureka clients, add this dependency instead:

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

Enabling the Eureka Server

Create a Spring Boot application and annotate the main class with @EnableEurekaServer to activate the service registry capabilities.

EurekaServerApplication.java

package com.example.eurekaserver;

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

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {

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

Ensure the following application.yml configuration is added to enable the Eureka dashboard:

server:
  port: 8761

eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

Start the Eureka Server and access the dashboard via http://localhost:8761.

Enabling Eureka Clients

For any service that needs to register with Eureka, add @EnableEurekaClient to the main application class.

ServiceApplication.java

package com.example.userservice;

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

@SpringBootApplication
@EnableEurekaClient
public class ServiceApplication {

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

Add the following Eureka client-specific configuration to application.yml:

spring:
  application:
    name: user-service

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

This ensures the service registers itself with the Eureka server.


Registering Services

To register services with Eureka, their spring.application.name must be uniquely defined. When the service starts, it automatically registers itself using the provided application.yml configuration.

Example Configuration for Multiple Services

User Service (user-service):

spring:
  application:
    name: user-service
server:
  port: 8081
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Order Service (order-service):

spring:
  application:
    name: order-service
server:
  port: 8082
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/

Both services will appear on the Eureka dashboard (e.g., under http://localhost:8761), showing their availability.

Verifying Registration

Visit the Eureka dashboard, and you should see all registered services, their status (UP/DOWN), and metadata like health and IP addresses.


Using Feign for Inter-Service Calls

When one microservice needs to call another, Feign simplifies the process by allowing you to define declarative HTTP clients.

Adding Feign Dependency

Add the following Feign dependency to your pom.xml for the services that need to communicate:

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

Enabling Feign

Use @EnableFeignClients in the main application class.

OrderServiceApplication.java

package com.example.orderservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableFeignClients
public class OrderServiceApplication {

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

Writing a Feign Client

Define an interface annotated with @FeignClient to declare the service you want to call.

UserClient.java

package com.example.orderservice.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

@FeignClient(name = "user-service")
public interface UserClient {

    @GetMapping("/users/{id}")
    String getUserById(@PathVariable("id") int id);
}

This Feign client will invoke the user-service endpoint /users/{id}. Feign handles service discovery dynamically via Eureka.

Example Usage of Feign Client

Use the Feign client in your service:

@RestController
@RequestMapping("/orders")
public class OrderController {

    private final UserClient userClient;

    public OrderController(UserClient userClient) {
        this.userClient = userClient;
    }

    @GetMapping("/{userId}")
    public String getOrderForUser(@PathVariable int userId) {
        String userDetails = userClient.getUserById(userId);
        return "Order created for user: " + userDetails;
    }
}

Load Balancing with Ribbon

Ribbon, a client-side load balancing library, is embedded in Feign by default. It automatically distributes traffic across multiple instances of a service.

How Ribbon Works

Ribbon uses the Eureka client to discover all available instances of a service. When a request is made, Ribbon selects an instance based on its configured load-balancing strategy (e.g., round-robin or random).

Example of Load Balancing

If you have two instances of user-service running (e.g., on ports 8081 and 8083), Ribbon will evenly distribute requests across both instances.

By default, Feign and Ribbon integrate seamlessly, requiring no additional configuration. However, you can customize Ribbon’s behavior using the application.yml file:

Custom Ribbon Configuration:

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

This changes the load-balancing strategy to a random distribution.


External Resources for Further Learning


Final Thoughts

By combining Spring Boot with Eureka and Feign, you can build scalable, resilient, and easy-to-maintain microservices. With service discovery, declarative HTTP clients, and built-in load balancing, these technologies remove much of the complexity involved in managing multiple services.

Follow the steps in this guide to set up your microservices architecture, and take full advantage of Spring Boot’s integration with Netflix OSS tools. Bookmark this guide as a reference for your future microservices development projects!

Similar Posts

Leave a Reply