Spring WebFlux: an introduction

Jeroen Sterken, 5 Feb 2018

Spring 5 is the first Spring framework that offers built-in support for reactive programming. This blog is an introduction to Spring WebFlux’s new functional programming model.

Late last year, seven Spring specialists from Faros headed out to San Francisco for SpringOne. (Check our blog for a short report. + link) One thing we couldn’t miss: reactive programming was a recurring theme throughout many of the presentations we attended. Of course, that has a lot to do with the Spring 5 release of last September. Spring 5 is the first in a series of Spring frameworks that have built-in support for reactive programming.

In this blog, we look at the new WebFlux module in Spring 5, offering support for non-blocking/async HTTP requests, following the principles of the reactive streams manifesto. This introduction is based on ‘New in Spring Framework 5.0: Functional Web Framework, a presentation we attended at SpringOne.

Reactive programming

Spring 5 is all about reactive programming. That model combines an asynchronous programming model for the more efficient use of resources (threads) with (big) data processing. The model uses, among other things, the concepts of publisher/subscriber and backpressure, to prevent publishers from engulfing their subscribers with data.

It is important to maintain the reactive model throughout all layers: from database to web. In this blog, we focus on the web with Spring WebFlux. (Read more about the reactive model here: Reactive programming, the basics.)

Spring WebFlux

In recent times, we saw the rise of a new type of servers, such as Netty and Undertow. These servers no longer take the servlet specification as a basis, but work more on a lower level, embracing the idea of non-blocking and asynchronous communication. However, the majority of existing servers and applications is still based on the servlet API. And we can’t throw that one overboard just like that…

Spring WebFlux can handle both. To make that possible, a new abstraction has been made – HTTP/Reactive Streams – which also provides a bridge to servlet API 3.1+. Previous servlet versions aren’t usable because they don’t or insufficiently support the asynchronous non-blocking model. 

So, we’re good for the asynchronous part. But what about the concept of data streams, where data is forwarded as soon as it is available? Traditional HTTP requests are initiated from the client. However, in a reactive model, we want the data from the publisher (server) to flow to the client as soon as it is available. In order to set up such client/server data streams, Spring WebFlux uses techniques such as Server Sent Events and web sockets. The combination of the efficient (re)use of threads by async/callbacks with client/server data streams allows us to build a completely new web model: Spring WebFlux.

Let’s get to work! In Spring Boot, we add WebFlux using this starter:

 

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-WebFlux</artifactId>

</dependency>

Functional programming model

Spring WebFlux offers a choice of two programming models: a model with annotations and a functional model.

The well-known Spring Web MVC model with annotations (such as @Controller) is a declarative model with callbacks.

 

@RestController

@RequestMapping("/person")

public class PersonController {

    @GetMapping("/{id}")

    public Mono<Person> getPersonById(@PathVariable String id) {

        return Mono.just(new Person(id));

    }

}

 

Please note the use of the new Mono type. Together with Flux, Mono is one of two basic types in the Reactor project, the underlying reactive framework in Spring 5. Mono is a type publisher with one result. Flux is a publisher that offers several results.

The second model – the functional programming model – uses Java 8 Lambdas to define routes. The main difference with the previous, declarative model is that the code fully defines request processing, including the response body’s lay-out.

 

@EnableWebFlux

@Configuration

public class MyConfiguration {

   

    @Bean

    RouterFunction<ServerResponse> myRouterFunction() {

        return route(GET("/person/{id}"),

                        request ->

                            ServerResponse.ok()

                                    .body(Mono.just(new Person(request.pathVariable("id"))), Person.class));

    }

}
 

@EnableWebFlux configures the Spring beans that are needed to activate the reactive mode, comparable to what @EnableWebMvc does for Spring Web MVC.

Server

With the routes defined, all we need now is an application server. In the Spring WebFlux code, you can start an application server that contains the necessary route definitions, without the need for a Spring application context. For that, we start from a routerFunction (like the one above), that we transform into an HttpHandler:

 

HttpHandler httpHandler = RouterFunctions.toHttpHandler(routes);

 

 

The HttpHandler abstraction was introduced in Spring 5. It allows the plug-in of a wide variety of reactive runtimes.

In the next step, we make a ReactorHttpHandlerAdapter to connect the handler to the Reactor Netty runtime:

 

ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter( httpHandler);


All we need to do now, is start a server based on the adapter. We are now ready to receive HTTP requests.

This is what the full code looks like:

 

public class MyWebApplication {

    public static void main(String[] args) {

        MyWebApplication app = new MyWebApplication();

        RouterFunction<ServerResponse> routes = app.getRoutes();

        HttpHandler httpHandler = RouterFunctions.toHttpHandler(routes);

        ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);

        HttpServer server = HttpServer.create("localhost", 8080);

        server.startAndAwait(adapter);

    }

    public RouterFunction<ServerResponse> getRoutes() {

        return RouterFunctions.route(GET("/person/{id}"),

                request ->

                        ServerResponse.ok()

                                .body(Mono.just(new Person(request.pathVariable("id"))), Person.class));

    }

}

Conclusion

This blog is a first introduction to Spring WebFlux. We showed how you can get started with the new functional API. Would you like to get to work right away? Make sure you also check this sample project: https://github.com/poutsma/web-function-sample  

About Faros

Faros is Xplore Group’s Spring competence center. We train our employees to become Spring Professional Developers. Over the years, we have been building experience through numerous Spring projects. Faros supplies the trainers for the official Spring Pivotal training sessions in Belgium and Europe.

www.faros.be

Faros