A real-world controller example with Spring 5: Web Reactive

7.7k views Asked by At

I want to be involved in a reactive programming world with Spring. As I realised, it gives me a choice between two different paradigms: the annotation-based (with well-known to us @Controller, @RequestMapping) and the reactive one (which is intended to resolve an "Annotation Hell").

My problem is a lack of understanding how a typical reactive controller will look like. There are three conceptual interfaces, which I can use in my controller class:

HandlerFunction<T> (1) - I define a method for each specific ServerRequest which returns a concrete HandlerFunction<T> instance, then register these methods with a router. Right?

RouterFunction (2) and FilterFunction (3) - Is there a specific place where all RequestPredicates with corresponding HandlerFunctions should be placed? Or can I do it separately in each controller (as I used to do with the annotation approach)? If so, how then to notify a global handler (router, if any?) to apply this router part from this controller?

It's how I see a reactive controller "template" by now:

public class Controller {
    // handlers
    private HandlerFunction<ServerResponse> handleA() {
        return request -> ok().body(fromObject("a"));
    }

    // router
    public RouterFunction<?> getRouter() {
        return route(GET("/a"), handleA()).and(
               route(GET("/b"), handleB()));
    }

    // filter
    public RouterFunction<?> getFilter() {
        return route(GET("/c"), handleC()).filter((request, next) -> next.handle(request));
    }
}

And, finally, how to say that it is a controller, without marking it with the annotation?

I've read the Spring reference and all posts related to this issue on the official blog. There is a plenty of samples, but all of them are pulled out of context (IMHO) and I can't assemble them into a full picture.

I would appreciate if you could provide a real-world example and good practices of how to organise interactions between these functions.

2

There are 2 answers

0
Juan Medina On BEST ANSWER

This is not a real world example, but so far Is how I view some kind of organization on this:

https://github.com/LearningByExample/reactive-ms-example

3
Sergii Getman On

As far as I concerned:

RouterFunction is the closest analogue to @Controller (@RequestMapping precisely) in terms of new Spring approach:

Incoming requests are routed to handler functions with a RouterFunction (i.e. Function>). A router function evaluates to a handler function if it matches; otherwise it returns an empty result. The RouterFunction has a similar purpose as a @RequestMapping annotation. However, there is an important distinction: with the annotation your route is limited to what can be expressed through the annotation values, and the processing of those is not trivial to override; with router functions the processing code is right in front of you: you can override or replace it quite easily.

Then instead of Spring Boot SpringApplication.run in main method your run server manually by :

// route is your route function
HttpHandler httpHandler = RouterFunctions.toHttpHandler(route); 
HttpServlet servlet = new ServletHttpHandlerAdapter(httpHandler);
Tomcat server = new Tomcat();
Context rootContext = server.addContext("",
System.getProperty("java.io.tmpdir"));
Tomcat.addServlet(rootContext, "servlet", servlet);
rootContext.addServletMapping("/", "servlet");
tomcatServer.start();

There are both reactive and non-reactive approach. It's illustrated on Spring github