¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
¡Acceso ilimitado 24/7 a todos nuestros libros y vídeos! Descubra la Biblioteca Online ENI. Pulse aquí
  1. Libros
  2. Java Spring
  3. Stack web reactiva Spring
Extrait - Java Spring Construya aplicaciones reactivas con una arquitectura de microservicios en un entorno Jakarta EE
Extractos del libro
Java Spring Construya aplicaciones reactivas con una arquitectura de microservicios en un entorno Jakarta EE Volver a la página de compra del libro

Stack web reactiva Spring

Introducción a la stack web reactiva

La stack web reactiva de Spring es un elemento de Spring Framework destinado a desarrollar aplicaciones web modernas y reactivas. Consiste principalmente en Spring WebFlux para crear servicios web reactivos y WebClient para interactuar de forma reactiva con servicios HTTP externos. Esta tecnología garantiza un excelente rendimiento, eficiencia de recursos y adaptabilidad, especialmente para microservicios o aplicaciones que requieren un alto nivel de reactividad. También admite los WebSockets para una comunicación bidireccional continua y RSocket para entornos de baja latencia. Esto permite a los desarrolladores diseñar aplicaciones web reactivas, robustas y adaptadas a contextos en tiempo real y altamente concurrentes.

Spring WebFlux es un módulo de Spring Framework diseñado para el desarrollo de aplicaciones web reactivas y asíncronas, ofreciendo un alto rendimiento y extensibilidad. Se distingue por su programación basada en flujos reactivos, la flexibilidad de su modelo de threading, la compatibilidad con WebSockets y RSocket para la comunicación en tiempo real, y un enfoque totalmente reactivo. WebFlux es compatible con varios servidores, entre ellos Tomcat, Jetty, Servlet, Netty y Undertow. Aunque Reactor Netty es el servidor por defecto con Spring Boot, los desarrolladores pueden optar por otros servidores añadiendo las dependencias adecuadas....

Núcleo reactivo

El módulo Spring Web proporciona soporte fundamental para las aplicaciones web reactivas con dos niveles de soporte para el procesamiento de peticiones del lado del servidor. En primer lugar, HttpHandler, que gestiona las solicitudes HTTP con I/O sin bloqueo. En segundo lugar, la API WebHandler, una versátil API de gestión de solicitudes en la que se basan los controladores anotados y los puntos finales (endpoints) funcionales. En el lado del cliente, el módulo proporciona un contrato de base ClientHttpConnector para las solicitudes HTTP con I/O no bloqueante y Reactive Streams, así como adaptadores para varios servidores, tales como Reactor Netty, el cliente reactivo Jetty y Apache HttpComponents.

El WebClient, utilizado en las aplicaciones, está construido sobre este contrato base. Además, el módulo proporciona códecs para serializar y deserializar el contenido de las solicitudes y respuestas HTTP, tanto para el cliente como para el servidor. Esto permite una gestión eficaz del flujo de datos y facilita el desarrollo de aplicaciones web reactivas.

HttpHandler

1. General

El módulo Spring Web ofrece HttpHandler, una interfaz básica para gestionar las solicitudes HTTP en aplicaciones web reactivas. Maneja las solicitudes entrantes y proporciona las respuestas apropiadas mientras utiliza I/O no bloqueante y soporta el backpressure de Reactive Streams. HttpHandler es compatible con varios servidores web reactivos como Reactor Netty, Undertow, Tomcat, Jetty u otros contenedores Servlet dependiendo del adaptador utilizado. Proporciona una abstracción de bajo nivel para la gestión de solicitudes y puede utilizarse para construir modelos de programación de alto nivel, como controladores anotados o endpoints funcionales. Usando el HttpHandler, las aplicaciones pueden procesar solicitudes sin bloquear el thread, mejorando la eficiencia del uso de los recursos del sistema. Esto permite que las aplicaciones sean de alto rendimiento y escalables, y que manejen un gran número de solicitudes simultáneas de forma eficiente sin sobrecargar el sistema. La elección del servidor web depende del contexto, y a menudo se prefiere la versión Reactor Netty por su rendimiento. Nos centramos principalmente en Reactor Netty. Sin embargo, otros servidores también son posibles, particularmente en entornos específicos que utilizan Kubernetes.

2. Para Reactor Netty

He aquí un ejemplo simplificado de un HttpHandlercon Reactor Netty:

public class SimpleHttpHandler { 
 
   public...

API de WebHandler

El paquete org.springframework.web.server ofrece una API web versátil basada en el contrato HttpHandler, que permite procesar las solicitudes a través de una cadena formada por WebExceptionHandler, WebFilter y un único WebHandler. Esta cadena se monta fácilmente mediante WebHttpHandlerBuilder, detectando automáticamente los componentes a través de ApplicationContexto registrándolos manualmente.

La API WebHandler amplía HttpHandler proporcionando funciones adicionales para aplicaciones web, como la gestión de sesiones de usuario, atributos de solicitud, datos de formulario, etc. Simplifica el desarrollo sin dejar de ser potente. Esta API superior permite construir modelos de programación específicos, como controladores anotados o endpoints funcionales. El WebHandler es una interfaz funcional que gestiona solicitudes (ServerRequest) y devuelve respuestas asíncronas (Mono<ServerResponse>...

WebHttpHandlerBuilder

La siguiente tabla enumera los componentes que WebHttpHandlerBuilder puede detectar automáticamente en un objeto ApplicationContext, o que se pueden registrar directamente con él.

  • WebExceptionHandler: 0 a N instancias para manejar las excepciones provenientes de la cadena WebFilter y el WebHandler de destino.

  • WebFilter: de 0 a N instancias para aplicar la lógica de interceptación antes y después del resto de la cadena de filtros y del WebHandler de destino. 

  • WebHandler: 1 instancia para gestionar la consulta.

  • WebSessionManager: 0 a 1 instancia para gestionar sesiones web expuestas a través de un método en ServerWebExchange. Utiliza DefaultWebSessionManager por defecto.

  • ServerCodecConfigurer: 0 a 1 instancia para acceder a instancias de HttpMessageReaderpara parser los datos de formulario y datos multipartes expuestos a través de métodos en ServerWebExchange. Utiliza ServerCodecConfigurer.create()por defecto.

  • LocaleContextResolver: 0 a 1 instancia para resolver el LocaleContext expuesto a través de un método en ServerWebExchange. Utiliza AcceptHeaderLocaleContextResolver por defecto.

  • ForwardedHeaderTransformer: 0 a 1 instancia para procesar los headers de "forwarded", ya sea extrayéndolas y borrándolas, o borrándolas solamente. No se utiliza por defecto.

Estos componentes pueden ser detectados y configurados automáticamente cuando...

ServerWebExchange

ServerWebExchange es una interfaz central de Spring WebFlux que representa el intercambio de información entre el cliente y el servidor cuando se procesa una solicitud HTTP. Encapsula toda la información relevante sobre la consulta entrante y proporciona métodos para acceder a esta información y modificar la respuesta enviada de vuelta al cliente. Veremos cómo utilizarlo a través de una serie de ejemplos.

Spring WebFlux

Spring WebFlux es la contrapartida reactiva de Spring MVC.

1. Aspectos clave para empezar

WebFlux está diseñado principalmente para crear servidores REST dinámicos. Aunque es efectivo en este dominio, no es recomendable para servir páginas como JSP, JSF, Thymeleaf, etc., ya que obtenemos mejores resultados con SPA (Single Page Applications). En el lado del cliente, preferimos utilizar WebClient, que es la alternativa a RestTemplate en Spring MVC. En este enfoque, nos centraremos inicialmente en la configuración de los servidores REST, los clientes WebClient y la integración de la seguridad a través de Spring Security. Entre bastidores, Spring WebFlux aprovecha Reactor Core, incluyendo sus implementaciones Flux y Mono.

Spring WebFlux ofrece dos modelos de programación:

  • El enrutamiento y la manipulación funcional

  • Los componentes reactivos basados en anotaciones

A continuación, le mostraremos cómo utilizar los distintos componentes mediante ejemplos que emplean estos dos modelos de programación, y después hablaremos de las características específicas de cada uno.

a. Seguridad mínima

Es necesario configurar la seguridad al mínimo mediante una clase de configuración:

@Configuration 
@EnableWebFluxSecurity 
public class ExempleSecurityConfig { 
   
  @Bean 
  public MapReactiveUserDetailsService userDetailsService() { 
    UserDetails user = User.withDefaultPasswordEncoder() 
      .username("user") 
      .password("user") 
      .roles("USER") 
      .build(); 
    return new MapReactiveUserDetailsService(user); 
  }   
} 

Esta configuración incluye autenticación de formulario y autenticación HTTP básica. Requiere que un usuario esté autenticado para poder acceder a las páginas. Además, se configuran una página de inicio de sesión y una página de cierre de sesión por defecto. También se definen cabeceras HTTP específicas de seguridad. Además, se han añadido medidas para contrarrestar los ataques...

WebSocket(s) reactivo(s)

El protocolo WebSocket, RFC 6455, proporciona un medio estandarizado para establecer una comunicación bidireccional full-duplex entre cliente y servidor a través de una única conexión TCP. Aunque se trata de un protocolo TCP distinto de HTTP, está diseñado para funcionar sobre HTTP, utilizando los puertos 80 y 443, lo que permite reutilizar las reglas de cortafuegos existentes.

Una interacción WebSocket comienza con una petición HTTP que utiliza la cabecera HTTP Upgrade para cambiar al protocolo WebSocket.

Tras un apretón de manos satisfactorio, el socket TCP subyacente permanece abierto, lo que permite al cliente y al servidor seguir enviando y recibiendo mensajes.

Tenga en cuenta que si un servidor WebSocket se ejecuta detrás de un servidor web (como nginx), probablemente sea necesario configurarlo para transferir las solicitudes de actualización de WebSocket al servidor WebSocket. Del mismo modo, si la aplicación está alojada en un entorno cloud, deberá comprobar las instrucciones del proveedor en relación con la compatibilidad con WebSocket. Aunque WebSocket está diseñado para ser compatible con HTTP, es crucial entender que estos dos protocolos conducen a arquitecturas y modelos de programación muy diferentes. En general, con HTTP, una aplicación es modelizada con múltiples URL accesibles a través de solicitudes. En cambio, con WebSocket, suele haber una única URL para la conexión inicial, y luego todos los mensajes de la aplicación pasan por esa misma conexión, lo que sugiere una arquitectura totalmente distinta. WebSocket puede hacer que una página web sea dinámica e interactiva. Sin embargo, a menudo basta con una combinación de AJAX y HTTP streaming o sondeo prolongado (long polling). Por ejemplo, para noticias o correo electrónico, una actualización de algunos minutos puede ser suficiente. Pero para juegos o aplicaciones financieras, el tiempo real es esencial. También es importante tener en cuenta que, en Internet, algunos proxies restrictivos pueden impedir las interacciones WebSocket. Esto significa que utilizar WebSocket para aplicaciones internas es más sencillo que para aplicaciones destinadas al público en general.

Spring Framework proporciona una API WebSocket con la que puede...

WebClient

El WebClient es la parte espejo del lado servidor de Spring WebFlux. También está destinado a ser utilizado con Spring MVC, ya que el RestTemplate corre el riesgo de desaparecer en favor del WebClient. El WebClient es una clase Spring WebFlux que permite realizar solicitudes HTTP de manera reactiva. Proporciona una interfaz fluida para realizar llamadas RESTful y recuperar respuestas de forma asíncrona.

Ya hemos visto algunos usos de WebClient en nuestros ejemplos anteriores.

A continuación, se muestra un ejemplo de uso de WebClient para realizar una solicitud GET a una API REST:

public class WebClientExample { 
   
  public static void main(String[] args) { 
    // Creación de un cliente WebClient 
    WebClient webClient = WebClient.create("https://api.example.com"); 
   
    // Ejemplo de solicitud GET a una API REST 
    Mono<String> responseMono = webClient.get() 
      .uri("/endpoint") 
      .retrieve() 
      .bodyToMono(String.class); 
   
    // Suscribirse a la respuesta y procesar los datos 
    responseMono.subscribe( 
      response -> System.out.println("Respusta : " + response), 
      error -> System.err.println("Error : " + error.getMessage()) 
    ); 
   
    // Esperar al final de la ejecución para que la petición 
    // tenga tiempo de finalizar   
    try {   
      Thread.sleep(3000);   
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    }   
  }   
} 

En este ejemplo, creamos un objeto WebClient usando WebClient.create(), luego hicimos una solicitud GET al URI "/endpoint" en la API REST utilizando el método get().uri("/endpoint"). A continuación, recuperamos...

RSocket

RSocket es un protocolo innovador diseñado para la comunicación entre aplicaciones, que permite intercambios bidireccionales a través de diferentes modos de transporte como TCP y WebSocket. Es un protocolo de aplicación que ofrece una semántica de flujo reactiva. Funciona, por ejemplo, como alternativa a HTTP.

Propone cuatro modelos principales de interacción:

  • Solicitud-Respuesta: se envía un mensaje y se espera una respuesta.

  • Solicitud -Flow: se envía un mensaje que da lugar a un flujo de respuestas.

  • Canal: intercambio continuo y bidireccional de mensajes.

  • Enviar y olvidar: envía un mensaje sin esperar respuesta.

Una vez establecida la conexión, no hay distinción estricta entre cliente y servidor; ambos pueden iniciar cualquier interacción. Esto da simetría, utilizándose los términos "solicitante" y "respondedor" para describirlos. Estas interacciones pueden denominarse "flujos de consultas" o simplemente "consultas".

Las ventajas de RSocket son numerosas, como la gestión reactiva de flujos, la regulación de solicitudes, la posibilidad de reanudar sesiones tras interrupciones, etc. Se basa en tecnologías como Reactor para sus implementaciones Java.

La conexión comienza cuando un cliente se conecta a un servidor a través de un transporte y envía una trama de configuración denominada SETUP. Una vez aceptada esta trama, pueden comenzar libremente los intercambios entre ambas partes. Cada solicitud enviada está marcada por una trama específica, y el respondedor devuelve tramas PAYLOAD como respuesta.

Los mensajes RSocket se componen de datos y metadatos, que pueden tener diversas funciones, como especificar una ruta o transmitir un token de seguridad. Los metadatos suelen ser específicos de una solicitud y se envían en el primer mensaje de esa solicitud. Algunas extensiones del protocolo definen formatos estándar para los metadatos, lo que permite, por ejemplo, combinar varias entradas de metadatos o especificar la ruta de una solicitud.

La implementación Java de RSocket está basada en Reactor. Los transportes para TCP y WebSocket se basan en Reactor Netty. Como biblioteca de flujos reactivos, Reactor simplifica la implementación de protocolos. Para aplicaciones, tiene sentido usar Fluxy Monocon operadores...

Conclusión

En conclusión, la utilización de la pila web reactiva de Spring con WebFlux, WebSocket y RSocket ofrece numerosas ventajas para el desarrollo de aplicaciones modernas de alto rendimiento. La programación reactiva permite gestionar eficazmente un gran número de conexiones simultáneas con un uso óptimo de los recursos de hardware, lo que la convierte en una solución ideal para aplicaciones web de alto rendimiento.

Con Spring WebFlux, podemos desarrollar aplicaciones reactivas que cumplan los requisitos de escalabilidad y reactividad de los entornos modernos. Los flujos reactivos (Mono y Flux) permiten gestionar las operaciones asíncronas de forma elegante y concisa, proporcionando una mejor experiencia de usuario.

La integración de WebSockets en la pila reactiva de Spring permite crear aplicaciones en tiempo real, facilitando la comunicación bidireccional entre servidor y cliente. Esto permite implementar funcionalidades en tiempo real como notificaciones, chat en directo, paneles de control dinámicos, etc.

RSocket proporciona comunicación reactiva entre microservicios con características únicas como gestión de peticiones y respuestas, soporte de recuperación de conexiones y mucho más. RSocket mejora la eficiencia de la comunicación entre microservicios y ofrece una mejor gestión de los errores y la congestión de la red.

Utilizando...