Spring Cloud is an umbrella of projects for patterns such as external configuration, routing, service discovery, load balancing, circuit breakers, messaging, and short-lived tasks. Add only the project that solves an observed distributed-system problem; a small Spring Boot application does not need Spring Cloud merely because it deploys to a cloud provider.
Spring Cloud provides tools for building distributed systems and microservices. It builds on Spring Boot to add patterns like service discovery, configuration management, API gateway, and circuit breaking.
| Component | Purpose | Technology |
|---|---|---|
| Service Discovery | Services register and find each other by name | Eureka, Consul |
| API Gateway | Single entry point for all client requests | Spring Cloud Gateway |
| Config Server | Centralized external configuration | Spring Cloud Config |
| Load Balancing | Distribute requests across service instances | Spring Cloud LoadBalancer |
| Circuit Breaker | Prevent cascading failures | Resilience4j |
| Feign Client | Declarative HTTP client for inter-service calls | OpenFeign |
// Eureka Server - Service Registry
// pom.xml dependency: spring-cloud-starter-netflix-eureka-server
package com.example.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer // Enables the Eureka service registry
public class EurekaServerApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp.class, args);
}
}
// application.yml for Eureka Server:
// server:
// port: 8761
// eureka:
// client:
// register-with-eureka: false # Server doesn't register itself
// fetch-registry: false
// Eureka Client - Microservice that registers with Eureka
// pom.xml dependency: spring-cloud-starter-netflix-eureka-client
package com.example.userservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient // Registers this service with Eureka
public class UserServiceApp {
public static void main(String[] args) {
SpringApplication.run(UserServiceApp.class, args);
}
}
# application.yml for User Service (Eureka Client)
spring:
application:
name: user-service # Service name used for discovery
server:
port: 8081
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
// pom.xml: spring-cloud-starter-openfeign
// Main class: @EnableFeignClients
package com.example.orderservice.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
// name = Eureka service name of the target microservice
@FeignClient(name = "user-service", fallback = UserFeignClientFallback.class)
public interface UserFeignClient {
@GetMapping("/api/users/{id}")
UserDto getUserById(@PathVariable("id") Long id);
@GetMapping("/api/users")
List<UserDto> getAllUsers();
}
// Fallback class for circuit breaker (Resilience4j)
@Component
class UserFeignClientFallback implements UserFeignClient {
@Override
public UserDto getUserById(Long id) {
return new UserDto(id, "Unknown", "N/A"); // Default response on failure
}
@Override
public List<UserDto> getAllUsers() {
return Collections.emptyList();
}
}
package com.example.orderservice.service;
import com.example.orderservice.client.UserFeignClient;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
private final UserFeignClient userFeignClient;
private final OrderRepository orderRepository;
public OrderService(UserFeignClient userFeignClient,
OrderRepository orderRepository) {
this.userFeignClient = userFeignClient;
this.orderRepository = orderRepository;
}
public OrderDto createOrder(Long userId, Long productId, int qty) {
// Call user-service via Feign (load-balanced automatically)
UserDto user = userFeignClient.getUserById(userId);
if (user == null) throw new RuntimeException("User not found: " + userId);
Order order = new Order(userId, productId, qty);
Order saved = orderRepository.save(order);
return new OrderDto(saved, user);
}
}
# Spring Cloud Gateway - routes all client traffic to microservices
# pom.xml: spring-cloud-starter-gateway
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
# Route to user-service (resolved via Eureka)
- id: user-service-route
uri: lb://user-service # lb:// = load-balanced via Eureka
predicates:
- Path=/api/users/**
filters:
- StripPrefix=0
- AddRequestHeader=X-Gateway, true
# Route to order-service
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
# Route with rate limiting
- id: product-service-route
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
server:
port: 8080
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
Spring Cloud uses release trains to align its independent projects. As of the current official project page, release train 2025.1.2 supports Spring Boot 4.0.x and 4.1.x. Always verify the current compatibility table and import the matching Spring Cloud BOM rather than assigning versions to individual modules.
A circuit breaker cannot repair an incorrect timeout or an overloaded dependency; define timeouts, bounded retries, fallback meaning, and observability together. Service discovery and centralized configuration also add operational dependencies, so prefer platform-native capabilities when they already meet the requirement.
Explore 500+ free tutorials across 20+ languages and frameworks.