DEV Community

Shubham Bhati
Shubham Bhati

Posted on

Service Discovery with Eureka and Spring Cloud: A Hands-On Tutorial

Spring Cloud Eureka Tutorial

Published 2026-07-28 by Shubham Bhati — Backend Engineer (Java 17, Spring Boot, Microservices).


Author: Shubham Bhati, Backend Engineer (Java 17, Spring Boot, Microservices)

Service Discovery with Eureka and Spring Cloud: A Hands-On Tutorial

Imagine your microservices architecture growing from a few services to dozens. Suddenly, hardcoding IP addresses or managing host files becomes a nightmare. Services go down, scale up or down dynamically, and your configuration files are constantly out of sync. This chaos directly impacts uptime and developer productivity. This is where service discovery becomes critical, and Spring Cloud Eureka offers a battle-tested solution. In this spring cloud eureka tutorial, we'll walk through setting up a Eureka server and client services to bring order to your distributed applications. Say goodbye to manual IP management and hello to dynamic service registration.


1. Setting Up the Eureka Server

The Eureka server acts as the central registry for your microservices. Services register themselves here and can discover other registered services. To start, create a new Spring Boot project. Add the Spring Cloud Eureka Server dependency to your pom.xml:

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

In your main application class, simply annotate it with @EnableEurekaServer:

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

Configure your application.yml to specify the server port and tell Eureka not to register itself or fetch registry information (it's the server, after all):

server:
  port: 8761 # Default Eureka server port

eureka:
  client:
    register-with-eureka: false # Server doesn't register itself
    fetch-registry: false       # Server doesn't fetch registry info
  instance:
    hostname: localhost
Enter fullscreen mode Exit fullscreen mode

Production Note: For high availability, you should run multiple Eureka server instances. They will peer with each other to synchronize registry data. This setup guards against a single point of failure. Also, monitor its memory footprint, especially in large deployments with many services frequently registering or renewing leases; it can become significant.


2. Registering Client Services

Now, let's register a microservice with our Eureka server. Create another Spring Boot project (e.g., product-service). Add the Spring Cloud Eureka Client dependency:

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

In your main application class, annotate it with @EnableDiscoveryClient:

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

Crucially, configure your client's application.yml to specify its name and the Eureka server's URL:

spring:
  application:
    name: product-service # This name is how other services find it

server:
  port: 8081

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka # Point to your Eureka server
Enter fullscreen mode Exit fullscreen mode

When product-service starts, it will register itself with the Eureka server running on 8761. You can verify this by visiting http://localhost:8761 in your browser. This dynamic registration is a cornerstone of scalable microservices, ensuring your service registry is always up-to-date with active instances.


3. Consuming Registered Services

With services registered, the next step is discovering and calling them. Spring Cloud makes this straightforward. In another client service (e.g., order-service), add the Eureka client dependency and configure it as shown in Section 2.

You can use DiscoveryClient to programmatically fetch service instances:

package com.example.orderservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;

@RestController
public class OrderController {

    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/products-info")
    public String getProductsInfo() {
        List<ServiceInstance> instances = discoveryClient.getInstances("product-service");
        if (instances != null && !instances.isEmpty()) {
            ServiceInstance serviceInstance = instances.get(0); // Basic load balancing
            String baseUrl = serviceInstance.getUri().toString();
            // In a real scenario, use a RestTemplate or WebClient to call the service
            return "Found product-service at: " + baseUrl;
        }
        return "product-service not found!";
    }
}
Enter fullscreen mode Exit fullscreen mode

A more common and powerful approach is to use RestTemplate with the @LoadBalanced annotation. This automatically integrates with Ribbon (Spring Cloud Netflix's client-side load balancer) to resolve service names to actual instances:

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class AppConfig {
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
Enter fullscreen mode Exit fullscreen mode

Then, you can inject and use it directly with the service name:

// Inside OrderController or another service class
@Autowired
private RestTemplate restTemplate;

@GetMapping("/call-product-service")
public String callProductService() {
    // Ribbon automatically intercepts "product-service" and replaces it with an actual instance URL
    return restTemplate.getForObject("http://product-service/api/products", String.class);
}
Enter fullscreen mode Exit fullscreen mode

Production Note: While @LoadBalanced RestTemplate simplifies service calls, consider adding circuit breakers (like Resilience4j or a custom retry mechanism) to your client services. This prevents cascading failures if a downstream service is slow or unavailable, improving the p99 latency of your entire system.


Common Pitfalls

  • Eureka Server Downtime: If your single Eureka server goes down, clients can't register or discover new services. Always deploy multiple Eureka instances for high availability.
  • Incorrect Service Names: Misspelling the spring.application.name in client application.yml or the name used in DiscoveryClient/RestTemplate calls prevents discovery. Names must match exactly.
  • Firewall Issues: Ensure network firewalls aren't blocking communication between your client services and the Eureka server, or between services themselves.
  • Caching Stale Data: Eureka clients cache service registry information. If a service goes down or changes frequently, clients might hold stale data briefly. Ensure eureka.client.registry-fetch-interval-seconds is appropriately configured for your use case, though the default (30s) is usually fine.

Conclusion

Eureka and Spring Cloud simplify the complex task of service discovery in microservices architectures. By following this spring cloud eureka tutorial, you've learned to set up a centralized registry, register your microservices, and enable them to find and communicate with each other dynamically. This setup dramatically improves the scalability, resilience, and maintainability of your applications, allowing you to focus on business logic rather than infrastructure concerns. Implement these patterns to build more robust and flexible distributed systems.


Spring Cloud Eureka Tutorial in production

Further Reading


Written by **Shubham Bhati* — Backend Engineer at AlignBits LLC, specializing in Java 17, Spring Boot, microservices, and AI integration. Connect on LinkedIn, GitHub, or read more at shubh2-0.github.io.*

Top comments (0)