<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies>
El siguiente paso es construir una primera versión del servicio REST de Hola Mundo en este caso utilizando la anotación @RequestMapping.
package com.arquitecturajava.router; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HolaRESTService { @RequestMapping("/hola") public String hola() { return "hola desde spring"; } }
Si ejecutamos el proyecto de Spring boot
Nos mostrará los datos sin ningún problema.
Spring 4.3 GetMapping ,PostMapping etc
A partir de la versión 4.3 de Spring Framework existe la posibilidad de tener unas anotaciones algo más compactas y más sencillas de leer que se encarguen cada una de ellas de uno de los verbos HTTP (get,post, put,delete) . Veamos la modificación que es necesario aplicar.
package com.arquitecturajava.router; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HolaRESTService2 { @GetMapping("/hola2") public String hola() { return "hola desde spring con getmapping"; } }
El resultado es prácticamente el mismo solo que la anotación nos ayuda a simplificar y facilitar la lectura.
Spring WebFlux Router
A partir de Spring 5 tenemos la opción de usar Spring WebFlux Router que nos permite mapear el servicio sin añadir anotaciones al propio contenido de nuestra clase. Algo que permite centralizar y clarificar las configuraciones dejando las clases más limpias. Para que todo nos funcione correctamente deberemos actualizar el proyecto pom.xml para usar programación reactiva.
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies>
Una vez realizada esta operación el siguiente paso es construir un servicio Reactivo con Monos o Fluxs.
package com.arquitecturajava.router; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @Service public class HolaRESTService3 { public Mono<String> hola() { return Mono.just("hola desde spring y configuracion funcional"); } }
El último paso es cambiar el fichero de configuración de Spring para que acepte una nueva ruta.
package com.arquitecturajava.router; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.ServerResponse.ok; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; @SpringBootApplication public class RouterApplication { public static void main(String[] args) { SpringApplication.run(RouterApplication.class, args); } @Bean RouterFunction<ServerResponse> holaRoute(HolaRESTService3 holaService) { return RouterFunctions.route(GET("/hola3"),req->ok().body(holaService.hola(),String.class)); } }
Como podemos observar la ruta en este caso se denomina /hola3 y esta disponible a traves de un mapeo que se hace con programación funcional . El servicio no incluye ningún RequestMapping ni RestResource.
Si ejecutamos el programa el nuevo servicio queda publicado:
Conclusiones
Las nuevas capacidades de programación Reactiva de Spring 5 nos aportan nuevos enfoques en la programación y la programación funcional suma a la hora de abordar configuraciones compleja.
Al usar webflux, qué ventaja ves de usar routing basado en funciones vs el @RestController de siempre que es igualmente soportado en su forma reactiva?
Una configuración más flexible a través del uso de programación funcional
Pero a mi modo de ver , añade complejidad al uso. Si comparamos los 2 sistemas, se puede ver fácilmente que el primer ejemplo, es mucho más entendible.
En el segundo, ya tenemos que empezar a sumar más complejidad, más clases, devuelve un tipo Mono,
pero que construye llamando a .just() ?? y tenemos que parsear con un String.class. ??
Supongo que las tendrá alguna ventaja , porque si es por claridad , personalmente, se pierde la sencillez inicial.
Es una buena opinión Rafa . Es evidente que las anotaciones son más claras y esta todo más integrado. Pero el enfoque funcional permitirá a futuro centralizar y sobre todo poder abordar situaciones de mayor complejidad a nivel configurativo
Muchas gracias
de nada 🙂