Programación Reactiva en Java con Project Reactor
La programación reactiva es un paradigma de desarrollo orientado a flujos de datos asíncronos y la propagación de cambios. En Java, este concepto se implementa a través de la especificación Reactive Streams y su implementación más popular: la biblioteca Project Reactor (parte del ecosistema Spring WebFlux).
A diferencia del código imperativo tradicional, donde el programa ejecuta comandos secuencialmente, el enfoque reactivo permite procesar datos a medida que llegan, sin bloquear los hilos de ejecución. Esto es especialmente importante para sistemas de alta carga, microservicios y aplicaciones con un gran número de solicitudes concurrentes.
Componentes principales de Reactor
La biblioteca proporciona dos tipos principales de secuencias reactivas:
- Mono<T> — representa un flujo que puede contener 0 o 1 elemento. Se utiliza para operaciones asíncronas individuales (por ejemplo, una solicitud HTTP, obtener un registro de la base de datos).
- Flux<T> — representa un flujo que puede contener de 0 a N elementos. Es adecuado para colecciones, flujos de eventos o datos que llegan en partes.
Ambos tipos implementan la interfaz Publisher de la especificación Reactive Streams y admiten el mecanismo de backpressure (contrapresión): la capacidad del suscriptor para controlar la velocidad de recepción de datos.
Ejemplo: creación y procesamiento de Flux
Veamos un ejemplo simple de creación de un flujo reactivo de números y su procesamiento:
import reactor.core.publisher.Flux;
public class ReactorExample { public static void main(String[] args) { Flux<Integer> numbers = Flux.just(1, 2, 3, 4, 5);
numbers .map(n -> n * 2) // transformación .filter(n -> n % 3 == 0) // filtrado .subscribe( data -> System.out.println("Recibido: " + data), error -> System.err.println("Error: " + error), () -> System.out.println("¡Completado!") ); }}En este ejemplo:
Flux.just()crea un flujo de cinco números.map()multiplica cada elemento por 2.filter()conserva solo los números múltiplos de 3.subscribe()inicia el procesamiento: muestra el resultado, maneja errores y señala la finalización.
Asincronía y trabajo con Mono
Reactor permite realizar operaciones asíncronas sin bloquear hilos. Por ejemplo, la simulación de una solicitud a un servicio remoto:
import reactor.core.publisher.Mono;import java.time.Duration;
public class AsyncExample { public static void main(String[] args) throws InterruptedException { Mono<String> asyncResult = Mono.fromSupplier(() -> { try { Thread.sleep(1000); // simulación de retardo } catch (InterruptedException e) { e.printStackTrace(); } return "Datos recibidos"; }).subscribeOn(Schedulers.boundedElastic()); // ejecutar en otro hilo
System.out.println("Solicitud enviada..."); asyncResult.subscribe(System.out::println); Thread.sleep(2000); // esperar a que termine }}Punto clave: la llamada a .subscribeOn() traslada la ejecución de la operación costosa a un hilo separado, sin bloquear el principal. El suscriptor recibirá el resultado de forma asíncrona.
Manejo de errores en flujos reactivos
A diferencia de try-catch, en la programación reactiva los errores se manejan mediante operadores:
Flux<String> fluxWithError = Flux.just("A", "B", "C") .map(s -> { if ("B".equals(s)) t También en la biblioteca
Autorización y autenticación en TypeScript: guía completa
Trabajo con Excel en Go (Golang): bibliotecas, ejemplos y herramientas
Autorización y autenticación en Rust: bibliotecas y herramientas
kotlinx-datetime en Kotlin: guía completa con ejemplos prácticos
Caché en TypeScript: biblioteca node-cache