Spring Boot vs Spring Cloud: Diferencias y Patrones de Diseño para Microservicios

Spring Boot vs Spring Cloud: Diferencias y Patrones de Diseño para Microservicios

Guía completa sobre las diferencias entre Spring Boot y Spring Cloud, incluyendo patrones de diseño como Circuit Breaker, Service Discovery, API Gateway y Saga Pattern.

7 min de lectura

Una de las preguntas más comunes en el ecosistema Java es: ¿cuál es la diferencia entre Spring Boot y Spring Cloud? En este artículo exploraremos ambas tecnologías, sus diferencias, y los patrones de diseño fundamentales para construir microservicios.

¿Qué es Spring Boot?

Spring Boot es un framework que simplifica la creación de aplicaciones Spring. Proporciona configuración automática, servidores embebidos y convenciones sobre configuración para acelerar el desarrollo.

Características principales

@SpringBootApplication
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
CaracterísticaDescripción
AutoconfigurationConfigura automáticamente beans basándose en las dependencias
StartersDependencias pre-configuradas para casos de uso comunes
Embedded ServerTomcat, Jetty o Undertow embebidos (sin WAR)
ActuatorEndpoints para monitoreo y métricas
CLIHerramienta de línea de comandos

Cuándo usar Spring Boot

  • Aplicaciones standalone
  • Microservicios individuales
  • APIs REST
  • Aplicaciones web monolíticas
  • Prototipos rápidos

¿Qué es Spring Cloud?

Spring Cloud es un conjunto de herramientas para construir sistemas distribuidos y aplicaciones cloud-native. Se construye sobre Spring Boot y proporciona patrones para gestionar la complejidad de arquitecturas de microservicios.

Componentes principales (2024.0.0 Moorgate)

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2024.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
ComponenteFunción
Config ServerGestión centralizada de configuración
EurekaRegistro y descubrimiento de servicios
GatewayAPI Gateway y enrutamiento
Resilience4jCircuit breaker y tolerancia a fallos
StreamMensajería con Kafka/RabbitMQ
Sleuth/MicrometerTrazabilidad distribuida

Cuándo usar Spring Cloud

  • Arquitecturas de microservicios
  • Sistemas distribuidos
  • Aplicaciones cloud-native
  • Cuando necesitas service discovery
  • Gestión centralizada de configuración

Diferencias Clave

AspectoSpring BootSpring Cloud
PropósitoCrear aplicaciones individualesCoordinar sistemas distribuidos
DependenciasPocas, ligeroMúltiples, más complejo
EnfoqueProductividad del desarrolladorGestión del tráfico de red
ServidorEmbebido (Tomcat/Jetty)Depende de la infraestructura
Configuraciónapplication.propertiesConfig Server centralizado
EscalabilidadVerticalHorizontal

Patrones de Diseño para Microservicios

1. Circuit Breaker Pattern

El patrón Circuit Breaker previene que una falla en un servicio se propague a otros servicios. Funciona como un interruptor eléctrico.

@Service
public class OrderService {

    private final PaymentClient paymentClient;

    @CircuitBreaker(name = "payment", fallbackMethod = "paymentFallback")
    public PaymentResponse processPayment(PaymentRequest request) {
        return paymentClient.process(request);
    }

    public PaymentResponse paymentFallback(PaymentRequest request, Exception ex) {
        // Respuesta alternativa cuando el servicio falla
        return PaymentResponse.builder()
            .status("PENDING")
            .message("Payment service temporarily unavailable")
            .build();
    }
}

Configuración con Resilience4j:

resilience4j:
  circuitbreaker:
    instances:
      payment:
        slidingWindowSize: 10
        failureRateThreshold: 50
        waitDurationInOpenState: 10000
        permittedNumberOfCallsInHalfOpenState: 3

Estados del Circuit Breaker:

CLOSED → (fallas > umbral) → OPEN → (timeout) → HALF_OPEN → (éxito) → CLOSED

                                              (falla) → OPEN

2. Service Discovery Pattern

El patrón Service Discovery permite que los servicios se encuentren dinámicamente sin configuración estática de IPs.

Eureka Server:

@SpringBootApplication
@EnableEurekaServer
public class DiscoveryServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(DiscoveryServerApplication.class, args);
    }
}

Eureka Client:

@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServiceApplication.class, args);
    }
}
# application.yml
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
  instance:
    preferIpAddress: true

Uso con RestClient (nuevo en 2024.0.0):

@Service
public class InventoryClient {

    private final RestClient restClient;

    public InventoryClient(@LoadBalanced RestClient.Builder builder) {
        this.restClient = builder
            .baseUrl("http://inventory-service")
            .build();
    }

    public InventoryResponse checkStock(String productId) {
        return restClient.get()
            .uri("/api/inventory/{productId}", productId)
            .retrieve()
            .body(InventoryResponse.class);
    }
}

3. API Gateway Pattern

El API Gateway actúa como punto de entrada único para todas las peticiones de clientes.

@SpringBootApplication
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

Configuración de rutas:

spring:
  cloud:
    gateway:
      routes:
        - id: order-service
          uri: lb://ORDER-SERVICE
          predicates:
            - Path=/api/orders/**
          filters:
            - StripPrefix=1
            - AddRequestHeader=X-Request-Source, API-Gateway

        - id: inventory-service
          uri: lb://INVENTORY-SERVICE
          predicates:
            - Path=/api/inventory/**
          filters:
            - StripPrefix=1
            - CircuitBreaker=name=inventoryCircuitBreaker,fallbackUri=forward:/fallback/inventory

Beneficios del API Gateway:

  • Autenticación y autorización centralizadas
  • Rate limiting
  • Logging y monitoreo
  • Transformación de requests/responses
  • Load balancing

4. Saga Pattern

El patrón Saga gestiona transacciones distribuidas a través de múltiples microservicios mediante una secuencia de transacciones locales.

Choreography (Coreografía)

Los servicios se coordinan mediante eventos sin un coordinador central:

// Order Service
@Service
public class OrderService {

    @Autowired
    private KafkaTemplate<String, OrderEvent> kafkaTemplate;

    @Transactional
    public Order createOrder(OrderRequest request) {
        Order order = orderRepository.save(
            Order.builder()
                .status(OrderStatus.PENDING)
                .items(request.getItems())
                .build()
        );

        // Emitir evento para que otros servicios reaccionen
        kafkaTemplate.send("order-events",
            new OrderCreatedEvent(order.getId(), order.getItems()));

        return order;
    }

    @KafkaListener(topics = "payment-events")
    public void handlePaymentResult(PaymentResultEvent event) {
        if (event.isSuccess()) {
            orderRepository.updateStatus(event.getOrderId(), OrderStatus.CONFIRMED);
        } else {
            // Compensación: cancelar orden
            orderRepository.updateStatus(event.getOrderId(), OrderStatus.CANCELLED);
        }
    }
}
// Payment Service
@Service
public class PaymentService {

    @KafkaListener(topics = "order-events")
    public void handleOrderCreated(OrderCreatedEvent event) {
        try {
            Payment payment = processPayment(event);
            kafkaTemplate.send("payment-events",
                new PaymentResultEvent(event.getOrderId(), true));
        } catch (Exception e) {
            kafkaTemplate.send("payment-events",
                new PaymentResultEvent(event.getOrderId(), false));
        }
    }
}

Orchestration (Orquestación)

Un coordinador central gestiona el flujo de la saga:

@Service
public class OrderSagaOrchestrator {

    private final OrderService orderService;
    private final PaymentClient paymentClient;
    private final InventoryClient inventoryClient;
    private final ShippingClient shippingClient;

    @Transactional
    public OrderResult executeOrderSaga(OrderRequest request) {
        Order order = null;
        Payment payment = null;
        InventoryReservation reservation = null;

        try {
            // Paso 1: Crear orden
            order = orderService.createOrder(request);

            // Paso 2: Reservar inventario
            reservation = inventoryClient.reserve(order.getItems());

            // Paso 3: Procesar pago
            payment = paymentClient.process(order.getId(), request.getPayment());

            // Paso 4: Programar envío
            shippingClient.schedule(order.getId());

            // Confirmar orden
            orderService.confirm(order.getId());

            return OrderResult.success(order);

        } catch (Exception e) {
            // Compensaciones en orden inverso
            compensate(order, payment, reservation);
            return OrderResult.failed(e.getMessage());
        }
    }

    private void compensate(Order order, Payment payment,
                           InventoryReservation reservation) {
        if (payment != null) {
            paymentClient.refund(payment.getId());
        }
        if (reservation != null) {
            inventoryClient.release(reservation.getId());
        }
        if (order != null) {
            orderService.cancel(order.getId());
        }
    }
}

5. Config Server Pattern

Centraliza la configuración de todos los microservicios:

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}
# Config Server application.yml
spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/company/config-repo
          default-label: main
          search-paths: '{application}'

Cliente de configuración:

# bootstrap.yml del microservicio
spring:
  application:
    name: order-service
  cloud:
    config:
      uri: http://localhost:8888
      fail-fast: true

Arquitectura Completa

                    ┌─────────────────┐
                    │   API Gateway   │
                    │ (Spring Cloud   │
                    │    Gateway)     │
                    └────────┬────────┘

           ┌─────────────────┼─────────────────┐
           │                 │                 │
    ┌──────▼──────┐   ┌──────▼──────┐   ┌──────▼──────┐
    │   Order     │   │  Payment    │   │  Inventory  │
    │  Service    │   │  Service    │   │  Service    │
    │(Spring Boot)│   │(Spring Boot)│   │(Spring Boot)│
    └──────┬──────┘   └──────┬──────┘   └──────┬──────┘
           │                 │                 │
           └─────────────────┼─────────────────┘

                    ┌────────▼────────┐
                    │  Eureka Server  │
                    │(Service Discovery)
                    └────────┬────────┘

                    ┌────────▼────────┐
                    │  Config Server  │
                    │ (Configuración) │
                    └─────────────────┘

Resumen: ¿Cuál elegir?

EscenarioRecomendación
Aplicación simple o monolitoSpring Boot
API REST standaloneSpring Boot
Sistema de microserviciosSpring Boot + Spring Cloud
Necesitas service discoverySpring Cloud (Eureka)
Configuración centralizadaSpring Cloud Config
Tolerancia a fallosSpring Cloud + Resilience4j
API GatewaySpring Cloud Gateway

Conclusión

Spring Boot y Spring Cloud son complementarios, no competidores:

  • Spring Boot es la base para crear microservicios individuales de forma rápida y eficiente
  • Spring Cloud proporciona las herramientas para coordinar y gestionar esos microservicios en un sistema distribuido

Los patrones de diseño como Circuit Breaker, Service Discovery, API Gateway y Saga son fundamentales para construir sistemas resilientes y escalables. Spring Cloud facilita la implementación de estos patrones con herramientas probadas en producción.


Fuentes: