Spring Boot Microservices Eureka Server Example

In this tutorial, we’ll create two Spring Boot microservices, register them with an Eureka server, and demonstrate service communication using Feign. We’ll be using Spring Boot 3.2+ and Spring Cloud 2023.x. 

Introduction to Eureka Server

Eureka Server is a service registry where microservices register and discover other services. This dynamic discovery mechanism helps manage communication in a distributed system. It eliminates the need for hardcoding service addresses, making the system more scalable and resilient.

How Microservices Use Eureka for Discovery

When a microservice registers with Eureka, it provides the server with details like its hostname, IP address, and port. Other microservices can then query the Eureka server to get this information and communicate dynamically.

For example:

  • Service Registration: When a microservice starts, it registers itself with Eureka by sending a POST request with its metadata (such as hostname, IP address, and port) to the Eureka server.
  • Service Discovery: Another microservice, instead of hardcoding the service address, queries Eureka to get the address and port of the service. This is especially useful when services are deployed across multiple instances and dynamically assigned ports.

Flow of the System

  1. Eureka Server: Acts as a central registry where microservices register.
  2. Microservices: Register with Eureka Server and discover other services.
  3. Service Discovery: Microservices query the Eureka Server to find the network locations (IP and port) of other microservices.

For example, the order-service will use Eureka to dynamically get the address and port of product-service instead of hardcoding the URL.

Prerequisites

  • JDK 17 or later
  • Maven or Gradle
  • IDE (IntelliJ IDEA, Eclipse, etc.)

Step 1: Set Up the Eureka Server

1.1 Create the Project

Use Spring Initializr to create a new project with the following dependency:

  • Eureka Server

1.2 Configure application.properties

Set up the application properties for the Eureka Server.

server.port=8761
spring.application.name=eureka-server
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false

Explanation:

  • server.port=8761: Sets the port for the Eureka Server.
  • spring.application.name=eureka-server: Names the application.
  • eureka.client.register-with-eureka=false: The Eureka Server should not register with another Eureka Server.
  • eureka.client.fetch-registry=false: The Eureka Server doesn’t fetch the registry from other servers.

1.3 Enable Eureka Server

Add the @EnableEurekaServer annotation to the main application class.

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);
    }
}

Explanation:

  • @EnableEurekaServer: Enables the Eureka Server functionality.

Step 2: Set Up product-service

2.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Eureka Discovery Client

2.2 Configure application.properties

Set up the application properties for product-service.

server.port=8081
spring.application.name=product-service
eureka.client.service-url.default-zone=http://localhost:8761/eureka/

Explanation:

  • server.port=8081: Sets the port for product-service.
  • spring.application.name=product-service: Names the application.
  • eureka.client.service-url.default-zone=http://localhost:8761/eureka/: Specifies the Eureka Server URL for service registration.

2.3 Enable Eureka Client

Add the @EnableDiscoveryClient annotation to the main application class.

package com.example.productservice;

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

@SpringBootApplication
@EnableDiscoveryClient
public class ProductServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServiceApplication.class, args);
    }
}

Explanation:

  • @EnableDiscoveryClient: Registers the microservice with Eureka Server for service discovery.

2.4 Create a Product Model

Create a simple Product model to represent product data.

package com.example.productservice;

public class Product {
    private String id;
    private String name;
    private double price;

    public Product(String id, String name, double price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    // Getters
    public String getId() { return id; }
    public String getName() { return name; }
    public double getPrice() { return price; }
}

2.5 Create a Controller

Create a controller to handle product-related requests.

package com.example.productservice;

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

@RestController
public class ProductController {

    @GetMapping("/products/{id}")
    public Product getProduct(@PathVariable String id) {
        return new Product(id, "Sample Product", 99.99);
    }
}

Explanation:

  • @RestController: Marks this class as a REST controller.
  • @GetMapping("/products/{id}"): Maps GET requests to /products/{id}.

Step 3: Set Up order-service

3.1 Create the Project

Use Spring Initializr to create a new project with the following dependencies:

  • Spring Web
  • Eureka Discovery Client
  • OpenFeign

3.2 Configure application.properties

Set up the application properties for order-service.

server.port=8082
spring.application.name=order-service
eureka.client.service-url.default-zone=http://localhost:8761/eureka/

3.3 Enable Feign Clients and Eureka Client

Enable Feign clients and Eureka client functionality by adding the @EnableFeignClients and @EnableDiscoveryClient annotations in the main application class.

package com.example.orderservice;

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

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

3.4 Create a Feign Client for product-service

Create a Feign client interface to communicate with product-service.

package com.example.orderservice;

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

@FeignClient(name = "product-service")
public interface ProductServiceClient {

    @GetMapping("/products/{id}")
    Product getProductById(@PathVariable String id);
}

How Eureka Works Here:

  • @FeignClient(name = "product-service"): This tells order-service that it should communicate with product-service. The name "product-service" is the name that was registered in the Eureka server when product-service started.

  • How Eureka Helps: Normally, to communicate with another service, you'd need to know where that service is located (its IP address and port). But thanks to Eureka, order-service doesn't need to know those details. Eureka works like a directory, so when order-service wants to talk to product-service, it just asks Eureka for the current address and port. Eureka then provides this information automatically, even if product-service has moved to a different location or port.

This means the communication between services becomes dynamic and flexible because Eureka handles the behind-the-scenes details of finding and connecting to product-service.

3.5 Create a Controller

Create a controller to handle order-related requests and use the ProductServiceClient to fetch product details.

package com.example.orderservice;

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

@RestController
public class OrderController {

    private final ProductServiceClient productServiceClient;

    public OrderController(ProductServiceClient productServiceClient) {
        this.productServiceClient = productServiceClient;
    }

    @GetMapping("/orders/{productId}")
    public String createOrder(@PathVariable String productId) {
        Product product = productServiceClient.getProductById(productId);
        return "Order created for product: " + product.getName() + " with price: $" + product.getPrice();
    }
}

Explanation:

  • ProductServiceClient productServiceClient: Injects the Feign client for communication with product-service.

Step 4: Run the Microservices

  1. Start the Eureka Server: Run the EurekaServerApplication class.
  2. Start product-service: Run the ProductServiceApplication class.
  3. Start order-service: Run the OrderServiceApplication class.

Step 5: Test the Communication

Use a browser or Postman to test the endpoints:

  • product-service: http://localhost:8081/products/1
  • order-service: http://localhost:8082/orders/1

The response from order-service should include product details fetched from product-service.

Conclusion

You have successfully set up two Spring Boot microservices and registered them with Eureka Server. The Eureka Server acts as a service registry, allowing microservices to discover and communicate with each other by querying for dynamic service addresses and ports. This setup demonstrates a scalable microservices architecture and can be extended to more services and complex interactions.

Comments