Programación reactiva con Spring 5 WebFlux

    Introducción

    Spring WebFlux es la respuesta de Spring al creciente problema de bloquear la arquitectura de E / S.

    A medida que los datos se vuelven cada vez más cruciales en nuestra era, los enfoques que adoptamos para recuperarlos y manipularlos cambian. Convencionalmente, la mayoría de los enfoques eran «bloqueantes», o mejor dicho, sincrónicos. Lo que esto significa es que acceder a un recurso impedía que la aplicación accediera / procesara otro hasta que se resolviera el recurso anterior.

    Esto estaba perfectamente bien con una cantidad limitada de datos y recursos, aunque con la creciente demanda de datos a través de aplicaciones de alto rendimiento, esto se convirtió en un gran problema.

    Los editores comenzaron a abrumar a los suscriptores y manejar los recursos uno por uno, al igual que tener un solo empleado trabajando en todo el supermercado, se volvió demasiado lento para una experiencia de usuario fluida.

    La solución es obvia: que más empleados manejen a los clientes. En términos de aplicaciones de software, esto significa un entorno de subprocesos múltiples y llamadas asincrónicas sin bloqueo.

    Pila reactiva de Spring

    La popular pila de servlets de Spring que comprende Spring MVC usa los métodos convencionales para acceder y procesar datos como llamadas sincrónicas. Con la introducción de Spring 5, la pila reactiva de Spring se construyó sobre Núcleo del reactor.

    La pila reactiva de Spring ofrece soporte adicional para Netty y contenedores Servlet 3.1+, que brindan un mayor rendimiento para aplicaciones reactivas:

     

    Crédito Spring

    Spring WebFlux

    Spring WebFlux es un módulo homólogo de Spring MVC. Donde Spring MVC implementa E / S síncronas y de bloqueo, Spring WebFlux implementa programación reactiva a través de Flujos reactivos.

    Por lo general, usará uno u otro, aunque también puede combinarlos.

    Dependencias de Spring WebFlux

    Con un proyecto Spring Boot simple inicializado a través de Spring Initializr, es suficiente agregar una sola dependencia:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
        <version>{version}</version>
    </dependency>
    

    los spring-boot-starter-webflux incluye spring-web, spring-webflux, spring-boot-starter, spring-boot-starter-reactor-netty, etc., por lo que no es necesario que exista ninguna otra dependencia.

    Para las aplicaciones que utilizan Gradle para la gestión de dependencias, Spring WebFlux se puede agregar en la aplicación build.gradle archivo:

    compile group: 'org.springframework.boot', name: 'spring-boot-starter-webflux', version: '2.2.2.RELEASE'
    

    Mono y Flux

    En Spring WebFlux, los datos devueltos de cualquier operación se empaquetan en un flujo reactivo. Hay dos tipos que incorporan este enfoque y son los componentes básicos de las aplicaciones WebFlux: Mono y Flux.

    Mono es una secuencia que devuelve cero elementos o un solo elemento (0..1), mientras que Flux es una secuencia que devuelve cero o más elementos (0..N).

    Mono por lo tanto, se usa cuando espera un resultado único (o ninguno), como recuperar un usuario único de la base de datos, mientras que Flux se utiliza cuando espera varios resultados o una colección de algún tipo.

    Controlador Spring WebFlux

    De manera similar a como usamos controladores en Spring MVC clásico, para la creación de API REST asíncronas, usamos el controlador WebFlux. Incluso las convenciones de nomenclatura son similares para garantizar una transición fácil entre estos dos enfoques.

    Para marcar una clase como controlador, usamos el @RestController anotación a nivel de clase.

    Tener Spring WebFlux y las dependencias de Reactor Core en la ruta de clases le permitirá a Spring saber que el @RestController es de hecho un componente reactivo y añade soporte para Mono y Flux.

    Configuración de Spring WebFlux

    Como es estándar con Spring Boot, manejaremos la configuración a través de anotaciones. los @Configuration y @EnableWebFlux las anotaciones marcan una clase como una clase de configuración y la gestión de beans de Spring la registrará:

    @Configuration
    @EnableWebFlux 
    public class WebFluxConfig {}
    

    Para utilizar o ampliar la API de configuración de WebFlux existente, puede ampliar la WebFluxConfigurer interfaz:

    @Configuration
    @EnableWebFlux 
    public class WebFluxConfig implements WebFluxConfigurer {}
    

    CORS con Spring WebFlux

    WebFlux también ofrece compatibilidad con CORS (intercambio de recursos de origen cruzado), muy similar a la pila de servlets Spring MVC. La configuración de CORS se puede establecer a nivel de proyecto, así como a niveles de controlador y método de controlador.

    Para agregar la configuración CORS a nivel de proyecto, necesita @Overrride la addCorsMappings() método del WebFluxConfigurer interfaz:

    @Configuration
    @EnableWebFlux 
    public class WebFluxConfig implements WebFluxConfigurer { 
        @Override
        public void addCorsMappings(CorsRegistry registry) {
            registry.addMapping("/api/**")
                .allowedOrigins("http://www.Pharos.sh.com")
                .allowedMethods("GET", "PUT", "DELETE")
                .allowedHeaders("testHeader")
                .allowCredentials(true);
        }
    }
    

    Y para agregar la configuración CORS a un nivel más granular, el @CrossOrigin se utiliza la anotación. Esto permite especificar detalles de CORS a nivel de controlador y método.

    Cuando @CrossOrigin se utiliza en el nivel de clase del controlador, todas las configuraciones de CORS a nivel de método heredan de la configuración de nivel de clase:

    @CrossOrigin(origins = "https://www.Pharos.sh.com")
    @RestController
    @RequestMapping("/resource") 
    public class ResourceController {
    
        @GetMapping("/{id}")
        public Mono<Resource> getResource(@PathVariable String id) {
    
        }
    }
    

    Seguridad con Spring Webflux

    Spring también ofrece las opciones de seguridad estándar para su marco WebFlux. Necesitas agregar @EnableWebFluxSecurity a nivel de clase para habilitar las configuraciones de seguridad en el proyecto:

    @EnableWebFluxSecurity
    public class WebfluxSecurity {
    
        @Bean
        public SecurityWebFilterChain springSecurityFilterChain(
          ServerHttpSecurity http) {
            http.csrf().disable()
              .authorizeExchange()
              .pathMatchers(HttpMethod.GET, "/resource/").hasRole("ADMIN")
              .pathMatchers("/**").permitAll()
              .and()
              .httpBasic();
            return http.build();
        }
    }
    

    Cliente web Spring WebFlux

    Spring WebFlux también incluye un cliente web reactivo para administrar llamadas REST. Reactor-Netty se utiliza por defecto para comunicarse con el servidor WebFlux.

    El objeto cliente de WebFlux se puede crear utilizando métodos de fábrica estáticos o mediante su método de construcción (más personalización).

    Los métodos de fábrica estática son WebClient.create() y WebClient.create(String baseUrl). Por otro lado el WebClient.builder ofertas siguiendo opciones para agregar más detalles al objeto del cliente web:

    • uriBuilderFactory
    • defaultHeader
    • defaultCookie
    • defaultRequest
    • filter
    • exchangeStrategies
    • clientConnector

    Veremos esto más de cerca en la sección de procedimiento donde se construye una aplicación de demostración.

    Aplicación de demostración

    Crearemos una API REST reactiva simple utilizando los componentes estándar de WebFlux, que actuarán como un servidor reactivo. Luego, se construirá una aplicación de cliente web reactiva, que recupera información de este servidor y procesa los datos.

    Servidor web WebFlux

    Repositorio

    Comencemos por sentar las bases para una aplicación reactiva mediante la creación de una interfaz de repositorio reactiva.

    public interface ResourceRepository extends ReactiveCrudRepository<Resource, String> {}
    

    Hemos ampliado nuestro repositorio de WebFlux ReactiveCrudRepository, que devolverá datos como Mono o Flux tipos de datos, dependiendo del número de elementos que se pueden recuperar.

    Para usar MongoDB con Spring WebFlux, agregaremos una clase de configuración que le dice a Spring que la base de datos debe manejarse como un componente reactivo:

    @EnableReactiveMongoRepositories
    public class MongoDbConfiguration extends AbstractReactiveMongoConfiguration {
    
        @Override
        public MongoClient reactiveMongoClient() {
            return MongoClients.create();
        }
    
        @Override
        protected String getDatabaseName() {
            return "testDatabase";
        }
    }
    

    Controlador

    Con nuestra capa de datos lista y configurada, creemos un controlador REST simple que recuperará Mono y Flux recursos a través de solicitudes GET:

    @RestController
    @RequestMapping("/resource")
    public class ResourceController {
    
        @Autowired
        ResourceRepository resourceRepository;
    
        @GetMapping("/{id}")
        public Mono<Resource> getResource(@PathVariable String id) {
            return resourceRepository.findById(id);
        }
    
        @GetMapping
        public Flux<Resource> getResources() {
            return resourceRepository.findAll();
        }
    }
    

    Aquí estamos usando nuestro reactivo ResourceRepository para encontrar un recurso usando el id procedente de la solicitud. Como estamos buscando una ID única, el resultado esperado es 1 registro (se encuentra el recurso con la ID pasada) o 0 registros (no hay registros en la base de datos), por lo tanto Mono se utiliza como tipo de retorno.

    Ya que findAll() puede devolver más de un elemento de recurso (si está presente), Flux se utiliza como tipo de retorno.

    Cliente web WebFlux

    Ahora que tenemos una aplicación REST básica configurada, creemos un cliente Spring WebFlux que puede enviar solicitudes a la aplicación REST de WebFlux.

    Para iniciar un cliente web, necesitamos crear un WebClient objeto usando la URL del servidor:

    public WebClient openConnection(String url) {
        client = WebClient.create(url);
        return client;
    }
    

    Una vez el WebClient se crea el objeto, podemos usarlo para realizar solicitudes al servidor web.

    Hagamos una solicitud al servidor, recuperando un recurso con el ID dado:

    public void getResourceById(String id) {
        Mono<Resource> result = client.get()
                .uri("/resource/{id}", "1")
                .retrieve()
                .bodyToMono(Resource.class);
    
        result.subscribe(System.out::println);
    }
    

    los bodyToMono() El método es responsable de empaquetar el cuerpo de la respuesta en un Mono.

    Del mismo modo, si el punto final de llamada devuelve datos como Flux luego podemos recuperarlo usando el siguiente método:

    public void getAllResources() {
        Flux<Resource> result = client.get()
                .uri("/resource")
                .retrieve()
                .bodyToFlux(Resource.class);
    
        result.subscribe(System.out::println);
    }
    

    Conclusión

    Spring Framework permite a los desarrolladores crear aplicaciones y API reactivas y sin bloqueo utilizando la pila WebFlux de Spring. WebFlux ofrece anotaciones muy similares a las que se utilizan en las aplicaciones clásicas de Spring MVC, lo que facilita a los desarrolladores la transición al código reactivo.

    En esta guía, hemos repasado los conceptos más importantes del marco WebFlux y hemos creado una aplicación de demostración para mostrarlos en la práctica.

    El código fuente se puede encontrar en GitHub.

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *