Microservices with Spring
Spring Boot makes each individual service trivially easy to build; Spring Cloud supplies the glue that makes a fleet of services work together — discovery, routing, centralized configuration, resilience, and tracing. This section walks through that toolkit pattern by pattern. Start here for the big picture, then follow the section in order.
The Spring approach to microservices
Each service is an ordinary Spring Boot application: a @RestController, a service layer, a repository, its own database. What changes is everything between services. Rather than hand-rolling discovery, load balancing, and config management, you compose battle-tested Spring Cloud components.
┌──────────────┐
client ───────► │ API Gateway │ (Spring Cloud Gateway)
└──────┬───────┘
│ lb:// (resolves via discovery)
┌────────────────────┼────────────────────┐
▼ ▼ ▼
┌───────────┐ ┌───────────┐ ┌────────────┐
│ Orders │ │ Inventory │ │ Payments │
│ service │ │ service │ │ service │
└─────┬─────┘ └─────┬─────┘ └─────┬──────┘
│ register/discover │ │
└──────────┬─────────┴──────────┬─────────┘
▼ ▼
┌──────────────────┐ ┌────────────────┐
│ Discovery Server │ │ Config Server │
│ (Eureka) │ │ (git-backed) │
└──────────────────┘ └────────────────┘
│ │
▼ traces + metrics
┌──────────────────────────────────┐
│ Zipkin / Tempo + Prometheus │
└──────────────────────────────────┘
The flow of a typical request:
- A client calls the API gateway — the single public entry point.
- The gateway resolves
lb://orders-serviceagainst the discovery server and load-balances across healthy instances. - The orders service pulls its configuration at startup from the config server.
- When orders needs inventory, it discovers and calls it with a load-balanced client, wrapped in a circuit breaker.
- Every hop carries a correlation id so a single trace tells the whole story.
A minimal service
Nothing exotic — a Spring Boot service in the fleet still looks like this:
@SpringBootApplication
public class OrdersApplication {
public static void main(String[] args) {
SpringApplication.run(OrdersApplication.class, args);
}
}
@RestController
@RequestMapping("/orders")
@RequiredArgsConstructor
public class OrderController {
private final OrderService service;
@GetMapping("/{id}")
public OrderResponse get(@PathVariable Long id) {
return service.findById(id);
}
}
What turns it into a cloud-native service is a handful of starters and properties, covered across this section.
Note: Spring Cloud is versioned by a release train aligned to Spring Boot. With Spring Boot 3.5 you use Spring Cloud 2024.x. See Spring Cloud Overview for the exact BOM setup.
The patterns this section covers
| Concern | Spring Cloud answer |
|---|---|
| Where is service X? | Service discovery (Eureka) |
| Single entry point, routing, auth | API gateway |
| Centralized, refreshable config | Config server |
| Spread calls across instances | Client-side load balancing |
| Survive a failing dependency | Circuit breaker (Resilience4j) |
| Service-to-service calls | OpenFeign / RestClient / messaging |
| Debug a request across services | Distributed tracing |
| Consistency across services | Saga pattern |
In This Section
- Monolith vs Microservices — the conceptual trade-offs and the modular monolith.
- Why Microservices? — real drivers, real costs, and when not to.
- Spring Cloud Overview — the BOM, release train, and core projects.
- Service Discovery (Eureka) — register and find services dynamically.
- API Gateway — Spring Cloud Gateway routes, predicates, and filters.
- Config Server — git-backed centralized configuration with refresh.
- Load Balancing — client-side load balancing with Spring Cloud LoadBalancer.
- Circuit Breaker (Resilience4j) — resilience: retries, fallbacks, bulkheads.
- Inter-Service Communication — sync vs async, timeouts, idempotency.
- Distributed Tracing — Micrometer Tracing across the fleet.
- Saga Pattern — distributed transactions and eventual consistency.