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.
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ística | Descripción |
|---|---|
| Autoconfiguration | Configura automáticamente beans basándose en las dependencias |
| Starters | Dependencias pre-configuradas para casos de uso comunes |
| Embedded Server | Tomcat, Jetty o Undertow embebidos (sin WAR) |
| Actuator | Endpoints para monitoreo y métricas |
| CLI | Herramienta 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>
| Componente | Función |
|---|---|
| Config Server | Gestión centralizada de configuración |
| Eureka | Registro y descubrimiento de servicios |
| Gateway | API Gateway y enrutamiento |
| Resilience4j | Circuit breaker y tolerancia a fallos |
| Stream | Mensajería con Kafka/RabbitMQ |
| Sleuth/Micrometer | Trazabilidad 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
| Aspecto | Spring Boot | Spring Cloud |
|---|---|---|
| Propósito | Crear aplicaciones individuales | Coordinar sistemas distribuidos |
| Dependencias | Pocas, ligero | Múltiples, más complejo |
| Enfoque | Productividad del desarrollador | Gestión del tráfico de red |
| Servidor | Embebido (Tomcat/Jetty) | Depende de la infraestructura |
| Configuración | application.properties | Config Server centralizado |
| Escalabilidad | Vertical | Horizontal |
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?
| Escenario | Recomendación |
|---|---|
| Aplicación simple o monolito | Spring Boot |
| API REST standalone | Spring Boot |
| Sistema de microservicios | Spring Boot + Spring Cloud |
| Necesitas service discovery | Spring Cloud (Eureka) |
| Configuración centralizada | Spring Cloud Config |
| Tolerancia a fallos | Spring Cloud + Resilience4j |
| API Gateway | Spring 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: