En el mundo del desarrollo Java empresarial, las aplicaciones deben ser resilientes, escalables y eficientes en la nube. Spring Boot ha sido el estándar para microservicios durante años, pero con el auge de Kubernetes, GraalVM y Java 21+, las demandas han evolucionado.
Spring Boot 3 consolidó la simplicidad con autoconfiguración, actuators y soporte para reactive programming, facilitando microservicios en Docker/Kubernetes. Sin embargo, arrastraba limitaciones: requería starters extras como Resilience4j, las compilaciones nativas eran experimentales y la observabilidad dependía de configuraciones manuales. En proyectos reales de integración empresarial, esto generaba boilerplate y overhead en memoria. El multiprocesamiento con virtual threads ayudaba, pero faltaba integración nativa para concurrency limits y retries sin librerías externas. Estrategias como Circuit Breakers manuales funcionaban, pero consumían recursos y complejizaban el código, no siendo la solución definitiva para apps cloud-native de alta disponibilidad.
Spring Boot 4 introduce varias mejoras clave, cada una con un impacto directo en la robustez, rendimiento y mantenibilidad de las aplicaciones:
- Resiliencia integrada (@Retryable, @ConcurrencyLimit, @EnableResilientMethods): Permite manejar fallos transitorios (reintentos, límites de concurrencia) sin añadir librerías externas, reduciendo complejidad y mejorando la disponibilidad del servicio.
- JSpecify (@NonNull/@Nullable): Aporta null-safety a nivel de compilación, evitando NullPointerException en producción y documentando de forma explícita las expectativas de cada API.
- Versionado de API automático: Facilita exponer distintas versiones de una misma API sin romper clientes existentes, simplificando la evolución de contratos.
- @HttpExchange (cliente HTTP declarativo): Sustituye código repetitivo de RestTemplate/WebClient por interfaces declarativas, reduciendo boilerplate y haciendo más legible y mantenible la integración con APIs externas.
- Autoconfiguración modular mejorada: Permite arrancar solo lo necesario, reduciendo consumo de memoria y tiempos de arranque en microservicios.
- Micrometer 2.x + OpenTelemetry: Ofrece métricas y trazas listas para usar, mejorando la observabilidad sin configuraciones manuales complejas.
- Jackson 3.0: Optimiza la serialización/deserialización JSON, con mejor rendimiento y compatibilidad con las nuevas APIs de Java.
- JUnit 6: Mejora la experiencia de testing con nuevas capacidades de parametrización y extensiones, facilitando baterías de pruebas más expresivas y mantenibles.
- Buildpacks Docker mejorados: Generan imágenes de contenedor más ligeras y optimizadas automáticamente, simplificando el camino a producción en entornos Docker/Kubernetes.
- Native images con GraalVM: Reduce el uso de memoria y el tiempo de arranque (con ahorros típicos del 30–50%), ideal para serverless y microservicios de alta densidad.
- Virtual threads por defecto en WebClient: Multiplica el throughput en aplicaciones I/O intensivas al manejar muchas peticiones concurrentes con menos recursos.
- SpEL con soporte para Optional: Permite expresiones más seguras y expresivas evitando null checks manuales.
- BeanRegistrar: Habilita el registro programático de beans en tiempo de ejecución, útil para escenarios dinámicos o plugins.
- RestTestClient: Simplifica la escritura de tests para endpoints REST, reduciendo código auxiliar y mejorando la legibilidad de las pruebas.
- Integración de null-safety en el contenedor (vía JSpecify): Añade coherencia entre anotaciones de null-safety y el ciclo de vida de beans.
- Compilación AOT: Elimina gran parte del overhead de reflexión, mejorando rendimiento y siendo clave para escenarios serverless y edge computing.
- Modo “free-threaded” optimizado: Reduce la penalización en aplicaciones monohilo y mejora el aprovechamiento de múltiples núcleos en escenarios concurrentes.
- Mensajes de error mejorados y coloreados: Hacen más rápido el diagnóstico de problemas, acortando el tiempo de depuración y aprendizaje de nuevas APIs.
Resiliencia nativa con @Retryable y @ConcurrencyLimit
Spring Boot 4 permite añadir resiliencia (reintentos y control de concurrencia) sin librerías externas, solo con anotaciones de primer nivel. Imagina un servicio que consume una API externa de catálogos de productos (o menús, usuarios, etc.) que de vez en cuando responde con errores 5xx o timeouts. En Spring Boot 3, lo habitual era usar Resilience4j o Spring Retry, añadir starter, configurar beans y escribir lógica de fallback. En Spring Boot 4, con resiliencia integrada, basta con anotar el método.
Se añaden las dependencias mínimas en pom.xml:
- spring-boot-starter-web
- spring-boot-starter-actuator (para ver métricas de reintentos/concurrencia)
- Versión de Spring Boot 4.x (ej. 4.0.0)
Versión de Spring en el pom
Dependencias necesarias en el pom
Además para que estas anotaciones funcionen correctamente, en la aplicación tenemos que añadir la siguiente anotación:
Anotación para activar las características
Configuración de resiliencia
Con esta anotación Spring envuelve los métodos anotados con proxies que gestionan reintentos, backoff, límites de concurrencia, etc., de forma transparente.
Método con resiliencia implementada
Este método llama a una endpoint que esta implementado en la aplicación para simular los posibles fallos de un API externa.
Método simulación fallos
Retryable reintenta automáticamente ante excepciones configuradas por defecto (RuntimeException, timeouts, etc.) hasta 3 veces con backoff exponencial.
Prueba
- Levantar la aplicación y lanzar varias peticiones concurrentes contra /api/catalog/1.
- Observar:
En los logs cómo se realizan los re intentos automáticos cuando el mock responde
con error. En la primera petición se ve como la llamada al API externa se recibe bien
en la primera llamada. En la segunda petición para el id 12 se ve como realiza los 3
reintentos hasta que recibe bien la información.
Logs de peticiones
Esta demo ilustra cómo Spring Boot 4 integra patrones de resiliencia directamente en el framework, simplificando un caso de uso muy frecuente en microservicios.
Cliente HTTP declarativo con @HttpExchange y OpenTelemetry
Esta prueba muestra cómo consumir APIs externas con un cliente declarativo soportado directamente por Spring Boot 4 y Spring Framework 7. Además se implementa un stack completo de observabilidad nativa con OpenTelemetry: métricas (Prometheus), trazas distribuidas (Tempo) y logs correlacionados (Loki), todo visible en Grafana sin código adicional.
Antes, el consumo HTTP en Spring solía hacerse con:
- RestTemplate (imperativo)
- WebClient (reactivo)
Ambos implican construir la llamada “a mano”: URL, headers, conversión de cuerpo, manejo de errores, etc. Con @HttpExchange, se define una interfaz y Spring genera el cliente automáticamente a partir de anotaciones.
- @HttpExchange define la configuración base para la interfaz (URL, formato, etc.).
@GetExchange, @PostExchange, @DeleteExchange definen los endpoints concretos de forma declarativa.
Servicio a API externa
Prueba
- Arranca la aplicación y realiza peticiones a /api/todos:
- GET /api/todos
- GET /api/todos/{id}
- Se observa que:
- No hay RestTemplate ni WebClient explícito en el controlador ni el servicio.
- Cualquier cambio de ruta, headers o baseUrl se actualiza en un solo punto.
Observabilidad
Para la prueba levantamos un Docker Compose que levanta 5 servicios coordinados que forman un sistema de observabilidad completo en producción:
- otel-collector (puerto 4318/9464): Punto único de entrada para toda la telemetría OTLP de la aplicación. Recepciona métricas, trazas y logs, y los redistribuye a los backends especializados (Prometheus, Tempo, Loki).
- prometheus (puerto 9090): Almacena y consulta métricas numéricas como latencia HTTP, throughput y uso JVM.
- grafana (puerto 3000): Interfaz unificada para visualizar dashboards . Detecta automáticamente datasources y muestra métricas/trazas/logs correlacionados.
- loki (puerto 3100): Base de datos de logs indexados por labels. Almacena logs estructurados de la app con trace_id para correlación.
- tempo (puerto 3200): Almacena trazas distribuidas. Permite seguir el flujo completo de una petición desde la entrada HTTP hasta la API externa.
Para configurar nuestra aplicación solo se añade esta la dependencia de opentelemetry al pom.xml,estándar de Spring Boot 4.
Para configurar nuestra aplicación solo se añade esta la dependencia de opentelemetry al pom.xml,estándar de Spring Boot 4:
Dependencia opentelemetry nativa
Luego para conectar con el collector se configura toda la telemetría en el applicaction.yml:
Configuración métricas, trazas y logs
Una vez configurado, mediante Grafana podremos ver las métricas mediante dashboards que consume de Prometheus, Tempo y Loki.
Dashboard en Grafana
Dashboard Observability en Grafana
Como se ve, la configuración es bastante sencilla y nos evita tener que añadir varias dependencias y configuraciones extra mas complejas.
Conclusión
Spring Boot 4 representa un salto cualitativo en el desarrollo Java, transformando desafíos históricos en fortalezas nativas que elevan la productividad. Su integración fluida de resiliencia, observabilidad zero-config y compilación AOT elimina complejidades innecesarias, permitiendo aplicaciones cloud-native rápidas y robustas con mínima configuración. Esta evolución posiciona a Spring como un framework dominante para microservicios modernos y arquitecturas escalables
Patricio Flores
Técnico de Software
ALTIA