How to do it...

Let us implement reactive services using HandlerFunction<T> and RouterFunction<T>. Follow these steps:

  1. Before anything else, implementing a functional web framework means there will be a need to set up and configure another reactive embedded server that will execute and run these independent services. Since the embedded Tomcat is the one running for the whole Spring Boot 2.0 application, it will be advisable if Netty, Jetty, or Undertow were used to listen and run these independent services. This recipe chose the Reactor Netty server as the dedicated server for these functional-based events. Thus, now include the Netty APIs from the webflux starter POM:
<dependency> 
   <groupId>org.springframework.boot</groupId> 
   <artifactId>spring-boot-starter-webflux</artifactId> 
</dependency> 
  1. Then, add another webflux@Configuration class to inject reactor.ipc.netty.http.server.HttpServer:
@Configuration 
@EnableWebFlux 
public class HttpServerConfig { 
       
   @Bean 
   public  NettyContext nettyContext(ApplicationContext context) { 
      HttpHandler handler =  
            DispatcherHandler.toHttpHandler(context); 
      ReactorHttpHandlerAdapter adapter =  
new ReactorHttpHandlerAdapter(handler); 
      HttpServer httpServer =  
HttpServer.create("localhost", Integer.valueOf("8095")); 
      return httpServer.newHandler(adapter).block(); 
   } 
} 
Do not use the existing port of the embedded Tomcat server to avoid conflicts. Moreover, the reactive AplicationContext is needed by Netty in order to listen to all registered functional web components such as HandlerFunction<?> and RouterFunction<?>.
  1. Unlike in the usual @Controller, this functional web framework model of Spring 5 requires all ServletRequest and ServletResponse to be internally managed by the reactive org.springframework.web.reactive.function.server.HandlerFunction. This API is implemented using lambda expressions, @FunctionalInterface, Spring Reactor, RxJava, or any combinations of them. Usually, a HandlerFunction is created inside a webflux configuration class:
@Configuration 
@EnableWebFlux 
public class ReactiveControllers { 
    
   public HandlerFunction<ServerResponse> routeMonoHandle(){ 
      HandlerFunction<ServerResponse> handlerMono = 
            request -> ok().body(Mono.just("Mono Stream"),  
                        String.class); 
      return handlerMono; 
   } 
    
   public HandlerFunction<ServerResponse> handlerFluxData(){ 
      HandlerFunction<ServerResponse> handlerFlux = 
             req -> ServerResponse.ok() 
.body(fromObject("Flux Stream from String")); 
          return handlerFlux; 
   } 
}
Do not apply the @Controller annotation since this is a @Configuration class.
  1. Another way of writing HandlerFunction<?> is to create a @Component class that will contain all its bare implementations such as DataHandler that is stored inside org.packt.spring.boot.handler:
@Component 
public class DataHandler { 
 
   public Mono<ServerResponse> fluxHello(ServerRequest req) { 
      return ok().body(Flux.just("Hello", "World!"),  
               String.class); 
   } 
 
   public Mono<ServerResponse> stream(ServerRequest req) { 
      Stream<String> streamData =  
            Stream.of("i", "love", "reactive", "programming") 
.sorted() 
            .map((str) -> str.toUpperCase() + " "); 
      Flux<String> flux = Flux.fromStream(streamData); 
         return ok().contentType(MediaType.APPLICATION_STREAM_JSON) 
.body(flux, String.class); 
   } 
} 
  1. All these HandlerFunction<?> or reactive services will not be returned as a ServetResponse without the request URL mapping. In the traditional MVC, the @RequestMapping annotation maps the request handler to a URL that is called by the client to execute the handler. In the functional web model, @RequestMapping will not be used, but a router called org.springframework.web.reactive.function.server.RouterFunction, which will route the request to the HandlerFunction<?> whenever it finds a match with its registered URL. The following are injected RouterFunction<?> to the handlers in the ReactiveControllers configuration class:
@EnableWebFlux 
public class ReactiveControllers { 
    
   // refer to sources 
    
   @Bean 
   public RouterFunction<?> routeMono() { 
        return route(GET("/mono" + "/stream"),  
               routeMonoHandle()); 
    } 
    
   @Bean 
   public RouterFunction<ServerResponse> handledRoute(){ 
      RouterFunction<ServerResponse> router =  
         route(GET("/routeFluxHandle"), handlerFluxData()); 
      return router; 
   } 
} 
  1. To utilize the DataHandler functions, inject this bean component to the ReactiveControllers configuration class and use method references or lambda expression to call these HandlerFunction implementations:
@Configuration 
@EnableWebFlux 
public class ReactiveControllers { 
    
   @Autowired 
   private DataHandler dataHandler; 
 
   // refer to sources 
          
   @Bean 
   public RouterFunction<ServerResponse> compundRoutes() { 
          return route(GET("/routeFlux"), dataHandler::fluxHello) 
                 .andRoute(GET("/stream"), dataHandler::stream); 
       } 
} 
The implementation of RouterFunction<?> here is quite complex, since it establishes two URL gateways to execute two separate HandlerFunction<?>.
  1. Save all files. Execute the clean spring-boot:run command to deploy the reactive application. Open a browser and run all the independent services like http://localhost:8095/stream.
Avoid using the context root of the Tomcat embedded server for the reason that Reactor Netty here is configured to stand as a separate and container-independent reactive server.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.107.152