Skip to content

Spring Cloud

Spring Cloud provides tools for building distributed systems and microservices. Key components: Service Discovery (Eureka), API Gateway (Spring Cloud Gateway), Config Server (centralized config), Circuit Breaker (Resilience4j), Load Balancing (Spring Cloud LoadBalancer), and Distributed Tracing (Micrometer Tracing / Zipkin). These solve cross-cutting concerns in microservice architectures.

┌─────────────────────────────────────────────────┐
│                  API Gateway                    │
│           (Spring Cloud Gateway)                │
└────────────────────┬────────────────────────────┘
         ┌───────────┼───────────┐
         ↓           ↓           ↓
   ┌──────────┐ ┌──────────┐ ┌──────────┐
   │ Service A│ │ Service B│ │ Service C│
   └─────┬────┘ └─────┬────┘ └──────────┘
         │             │
         └──────┬──────┘
   ┌────────────────────┐   ┌─────────────────┐
   │  Service Registry  │   │  Config Server  │
   │     (Eureka)       │   │                 │
   └────────────────────┘   └─────────────────┘

Service Discovery (Eureka)

In microservices, instances spin up/down dynamically — hardcoding URLs doesn't work. Eureka is a service registry: each service registers itself and discovers others by name. Use @LoadBalanced RestTemplate to call services by name (e.g., http://user-service/api/users) with automatic client-side load balancing.

Deep Dive: Eureka Setup

Server:

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApp { ... }
server.port: 8761
eureka.client:
  register-with-eureka: false
  fetch-registry: false

Client (each microservice):

spring.application.name: order-service
eureka.client.service-url.defaultZone: http://localhost:8761/eureka/

Service-to-service call:

@Bean @LoadBalanced
public RestTemplate restTemplate() { return new RestTemplate(); }

// Use service name, not URL
restTemplate.getForObject("http://user-service/api/users/{id}", User.class, userId);


API Gateway

Spring Cloud Gateway is the single entry point for all microservice requests. Handles routing (path-based to services), filtering (auth, logging, rate limiting), load balancing (via lb://), and circuit breaking. Replaces Zuul (deprecated). Built on reactive stack (Spring WebFlux).

Deep Dive: Route Configuration
spring.cloud.gateway:
  routes:
    - id: user-service
      uri: lb://user-service
      predicates:
        - Path=/api/users/**
      filters:
        - StripPrefix=1
    - id: order-service
      uri: lb://order-service
      predicates:
        - Path=/api/orders/**
      filters:
        - name: CircuitBreaker
          args:
            name: orderCB
            fallbackUri: forward:/fallback/orders

Custom filter:

@Component
public class AuthFilter implements GatewayFilter, Ordered {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !isValid(token)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    }
}


Config Server

Centralized configuration for all microservices, backed by Git, filesystem, or Vault. Services connect via spring.config.import. Config changes can be refreshed at runtime using @RefreshScope and POST to /actuator/refresh. Supports profile-specific and service-specific config files.

Deep Dive: Setup

Server:

@SpringBootApplication @EnableConfigServer
public class ConfigServerApp { ... }
spring.cloud.config.server.git:
  uri: https://github.com/myorg/config-repo
  default-label: main

Client:

spring.config.import: configserver:http://localhost:8888
spring.application.name: order-service  # Loads order-service.yml

Runtime refresh:

@RefreshScope
@RestController
public class MyController {
    @Value("${feature.flag}")
    private boolean featureEnabled;  // Re-read on /actuator/refresh
}


Circuit Breaker (Resilience4j)

When a downstream service is down, calls pile up causing cascading failure. A circuit breaker monitors failure rate and opens the circuit (stops calls) when failures exceed a threshold. States: CLOSED (normal) → OPEN (failing, use fallback) → HALF_OPEN (test recovery). Resilience4j also provides retry, rate limiter, bulkhead, and time limiter.

Deep Dive: Configuration & Usage
CLOSED → (failures reach threshold) → OPEN
  ↑                                      │
  │         (wait duration)              ↓
  └──── CLOSED ←── (success) ←── HALF_OPEN
resilience4j.circuitbreaker.instances.userService:
  sliding-window-size: 10
  failure-rate-threshold: 50
  wait-duration-in-open-state: 10s
  permitted-number-of-calls-in-half-open-state: 3
@CircuitBreaker(name = "userService", fallbackMethod = "fallback")
public User getUser(Long userId) {
    return restTemplate.getForObject("http://user-service/api/users/" + userId, User.class);
}

private User fallback(Long userId, Throwable ex) {
    return cachedUserService.getCachedUser(userId);
}

Distributed Tracing

A single request may traverse multiple services. Distributed tracing assigns a unique trace ID propagated across all services, letting you track the full request path. Spring Boot 3 uses Micrometer Tracing with exporters like Zipkin. Trace IDs appear automatically in logs.

Deep Dive: Setup
management:
  tracing:
    sampling.probability: 1.0  # Sample 100% of requests
  zipkin:
    tracing.endpoint: http://localhost:9411/api/v2/spans

Trace IDs in logs:

2024-01-15 [order-service,traceId=abc123,spanId=def456] Processing order


Common Interview Questions

Common Interview Questions
  • What is Spring Cloud? Name its key components.
  • What is service discovery? How does Eureka work?
  • What is an API Gateway? Why use it?
  • What is a circuit breaker? Explain its states.
  • What is the Config Server? Why centralize configuration?
  • What is distributed tracing?
  • How does client-side load balancing work with @LoadBalanced?
  • What is @RefreshScope?
  • How do you handle cascading failures in microservices?