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 *