Spring Cloud Basics

SkillMonitoring & ops

Spring Cloud patterns for microservices in Spring Boot 3.x. Covers Service Discovery, Config Server, API Gateway, Circuit Breaker, Load Balancing, and Distributed Tracing.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Spring Cloud Basics skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/backend-frameworks/spring-cloud-basics/SKILL.md and read by ahel’s review.

Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│                        API Gateway                               │
│                    (Spring Cloud Gateway)                        │
└───────────────────────────┬─────────────────────────────────────┘
                            │
┌───────────────────────────▼─────────────────────────────────────┐
│                     Service Discovery                            │
│                    (Eureka / Consul)                             │
└──────────┬─────────────────┬─────────────────┬──────────────────┘
           │                 │                 │
    ┌──────▼──────┐   ┌──────▼──────┐   ┌──────▼──────┐
    │  Service A  │   │  Service B  │   │  Service C  │
    │  (3 inst.)  │   │  (2 inst.)  │   │  (1 inst.)  │
    └─────────────┘   └─────────────┘   └─────────────┘
           │                 │                 │
           └─────────────────┼─────────────────┘
                             ▼
                    ┌────────────────┐
                    │  Config Server │
                    └────────────────┘

Quick Start - Eureka

Server

@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false

Client

spring:
  application:
    name: product-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    prefer-ip-address: true

Full Reference: See service-discovery.md for Eureka HA and Config Server.


Quick Start - API Gateway

spring:
  cloud:
    gateway:
      routes:
        - id: product-service
          uri: lb://product-service
          predicates:
            - Path=/api/products/**
          filters:
            - StripPrefix=0

Full Reference: See gateway.md for custom filters and programmatic routes.


Quick Start - Circuit Breaker

@Service
public class ProductClient {

    @CircuitBreaker(name = "productService", fallbackMethod = "fallback")
    @Retry(name = "productService")
    public List<Product> getProducts() {
        return restClient.get()
            .uri("http://product-service/api/products")
            .retrieve()
            .body(new ParameterizedTypeReference<>() {});
    }

    private List<Product> fallback(Exception e) {
        return List.of();
    }
}
resilience4j:
  circuitbreaker:
    instances:
      productService:
        sliding-window-size: 10
        failure-rate-threshold: 50
        wait-duration-in-open-state: 10s

Full Reference: See resilience.md for Retry, Bulkhead, Rate Limiter, Feign.


Service Communication Pattern

@Service
@RequiredArgsConstructor
public class OrderService {

    private final ProductClient productClient;
    private final InventoryClient inventoryClient;
    private final PaymentClient paymentClient;

    @Transactional
    public Order createOrder(CreateOrderRequest request) {
        // 1. Verifica prodotti
        List<Product> products = request.items().stream()
            .map(item -> productClient.getProductById(item.productId()))
            .toList();

        // 2. Verifica inventario
        boolean available = inventoryClient.checkAvailability(request.items());
        if (!available) {
            throw new InsufficientInventoryException("Items not available");
        }

        // 3. Crea ordine
        Order order = Order.create(request.customerId(), products, request.items());
        order = orderRepository.save(order);

        // 4. Riserva inventario
        inventoryClient.reserveItems(order.getId(), request.items());

        // 5. Processa pagamento (con rollback)
        try {
            PaymentResult payment = paymentClient.processPayment(
                new PaymentRequest(order.getId(), order.getTotal())
            );
            order.setPaymentId(payment.paymentId());
            order.setStatus(OrderStatus.PAID);
        } catch (PaymentFailedException e) {
            inventoryClient.releaseReservation(order.getId());
            order.setStatus(OrderStatus.PAYMENT_FAILED);
            throw e;
        }

        return orderRepository.save(order);
    }
}

Load Balancer

@Configuration
public class LoadBalancerConfig {

    @Bean
    @LoadBalanced
    public RestClient.Builder loadBalancedRestClientBuilder() {
        return RestClient.builder();
    }
}

// Usage: use service name instead of host
restClient.get()
    .uri("http://product-service/api/products")
    .retrieve()
    .body(new ParameterizedTypeReference<>() {});

Distributed Tracing

management:
  tracing:
    sampling:
      probability: 1.0
  zipkin:
    tracing:
      endpoint: http://localhost:9411/api/v2/spans

logging:
  pattern:
    level: "%5p [${spring.application.name:},%X{traceId:-},%X{spanId:-}]"

Best Practices

DoDon't
Use Service Discovery for all servicesHardcode service URLs
Implement Circuit Breaker with fallbackIgnore failures
Centralize config with Config ServerDuplicate configuration
Add distributed tracingMiss observability
Use API Gateway as single entry pointExpose services directly

When NOT to Use This Skill

  • Single service - Spring Cloud adds unnecessary complexity
  • Kubernetes native - Use K8s service discovery, ConfigMaps
  • Simple deployments - Overhead not justified
  • Specific components - Use dedicated skills for deep dives

Common Pitfalls

ErrorCauseSolution
No instances availableService not registeredVerify Eureka registration
Connection refusedService downImplement Circuit Breaker
TimeoutService slowConfigure appropriate timeouts
Config not loadingConfig server unreachableUse fail-fast: false or fallback
Load balancing not workingMissing @LoadBalancedAnnotate RestClient builder

Anti-Patterns

Anti-PatternProblemSolution
Hardcoding service URLsNo discovery benefitUse service names
No circuit breakerCascading failuresAdd Resilience4j
Missing retryTransient failuresConfigure retry with backoff
No config refreshChanges need redeployUse @RefreshScope
Synchronous everywhereTight couplingUse async where appropriate

Quick Troubleshooting

ProblemDiagnosticFix
Service not foundCheck Eureka dashboardVerify registration
Config not loadingCheck config server logsVerify path, profile
Circuit always openCheck failure thresholdTune thresholds
Gateway routing failsCheck predicatesVerify route config
Load balancing not workingCheck @LoadBalancedAdd annotation

Reference Files

FileContent
service-discovery.mdEureka Server/Client, Config Server
gateway.mdAPI Gateway, Filters, Routes
resilience.mdCircuit Breaker, Retry, Feign, Testing

External Documentation

Signals

GitHub stars
33
Forks
8
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
spring-cloud-basics
Source
github.com/claude-dev-suite/claude-dev-suite