Volver a Spring Boot Intermedio

Microservicios con Spring Boot

Los microservicios descomponen un monolito en servicios independientes y desplegables que se comunican por red.

¿Por qué Microservicios?

  • Despliegue independiente — actualiza un servicio sin tocar los demás
  • Diversidad tecnológica — cada servicio puede usar un stack diferente
  • Escalabilidad — escala solo los servicios bajo carga
  • Aislamiento de fallos — los errores no se propagan al sistema completo

Resumen de Spring Cloud

<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2023.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency>

Descubrimiento de Servicios con Eureka

// Servidor Eureka @SpringBootApplication @EnableEurekaServer public class ServidorDescubrimiento { public static void main(String[] args) { SpringApplication.run(ServidorDescubrimiento.class, args); } }
# application.yml del servidor Eureka server: port: 8761 eureka: client: register-with-eureka: false fetch-registry: false
# application.yml del servicio cliente spring: application: name: servicio-productos eureka: client: serviceUrl: defaultZone: http://localhost:8761/eureka/

API Gateway

spring: cloud: gateway: routes: - id: servicio-productos uri: lb://servicio-productos predicates: - Path=/api/productos/** filters: - StripPrefix=1 - id: servicio-pedidos uri: lb://servicio-pedidos predicates: - Path=/api/pedidos/**

Comunicación entre Servicios con OpenFeign

// Declaración del cliente Feign @FeignClient(name = "servicio-productos", fallback = ProductoClienteFallback.class) public interface ProductoCliente { @GetMapping("/api/productos/{id}") ProductoResponse obtenerProducto(@PathVariable Long id); @PutMapping("/api/productos/{id}/stock") void actualizarStock(@PathVariable Long id, @RequestBody ActualizarStockRequest req); } // Uso en el servicio de pedidos @Service public class ServicioPedidos { private final ProductoCliente productoCliente; public Pedido crearPedido(CrearPedidoRequest request) { ProductoResponse producto = productoCliente.obtenerProducto(request.getProductoId()); // ... crear pedido } }

Circuit Breaker con Resilience4j

// Implementación de fallback @Component public class ProductoClienteFallback implements ProductoCliente { @Override public ProductoResponse obtenerProducto(Long id) { return new ProductoResponse(id, "Producto Desconocido", BigDecimal.ZERO); } @Override public void actualizarStock(Long id, ActualizarStockRequest req) { // registrar fallo, reintentar después por cola de mensajes } } // Circuit breaker programático @Service public class ServicioProductos { private final CircuitBreakerFactory cbFactory; public ProductoResponse obtenerProducto(Long id) { CircuitBreaker cb = cbFactory.create("servicio-productos"); return cb.run( () -> productoCliente.obtenerProducto(id), throwable -> new ProductoResponse(id, "No disponible", BigDecimal.ZERO) ); } }
resilience4j: circuitbreaker: instances: servicio-productos: sliding-window-size: 10 failure-rate-threshold: 50 wait-duration-in-open-state: 10s

Trazado Distribuido con Micrometer

<dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-tracing-bridge-brave</artifactId> </dependency> <dependency> <groupId>io.zipkin.reporter2</groupId> <artifactId>zipkin-reporter-brave</artifactId> </dependency>
management: tracing: sampling: probability: 1.0 zipkin: tracing: endpoint: http://localhost:9411/api/v2/spans

Docker Compose para Desarrollo Local

version: '3.8' services: eureka: image: steeltoeoss/eureka-server ports: - "8761:8761" postgres: image: postgres:15 environment: POSTGRES_PASSWORD: secreto ports: - "5432:5432" zipkin: image: openzipkin/zipkin ports: - "9411:9411" servicio-productos: build: ./servicio-productos environment: SPRING_PROFILES_ACTIVE: docker EUREKA_CLIENT_SERVICEURL_DEFAULTZONE: http://eureka:8761/eureka/ depends_on: - eureka - postgres