Getting started with Spring 5

In late September 2017, Spring 5 has finally been release to GA introducing WebFlux and reactive Spring which caught most of the attention in this release.

In this post I will layout the road to writing a reactive backend application using Spring 5.

Reactive Spring

The reactive Spring stack adds support for non-blocking Servlets supporting reactive streams back pressure.

So what does this mean?

The term “reactive” refers to programming models that are built around reacting to change — network component reacting to I/O events, UI controller reacting to mouse events, etc. In that sense non-blocking is reactive because instead of being blocked we are now in the mode of reacting to notifications as operations complete or data becomes available.

This should allow you to use less resources or alternatively consume higher volumes of actions.

The reactive library

Spring 5 based its reactive support on the Reactor Java library also made by Pivotal.

Let us review the following new types:

  • Publisher A pushblisher provides a (potentially) unbounded number of elements to its subsribers.

  • Mono A mono is a publisher which will emit one element or an error.

  • Flux A flux is a publisher which will emit 0 to N elements and then finish.

However, there are 2 ways to embed this library into your application and these do not interact as they are based on different implementations:

  • Use the Spring WebFlux library, by for example add the Spring boot designated starter: spring-boot-starter-webflux.

  • Use Spring MVC, Spring 5 expanded the Spring MVC suite to include reactive controllers, clients and for Servlet containers that support the reactive framework.

Why are there 2 different libraries?

The necessity of Spring WebFlux instead of working Spring MVC, is that the Spring WebFlux is a more inclusive support for the reactive library. This includes running on non-Servlet containers, such as Netty, and some coding goodies such as the functional endpoints definition which we will review later on.

How can you choose?

My suggestion is to consider the following:

  • Are you expanding an existing Spring MVC application? If so, the answer is clear use Spring MVC

  • If you need a lightweight reactive application, go with WebFlux

  • Though IMHO the learning curve is not high, you should consider how long it will take you and your team to learn Spring WebFlux

The reactive server

Once you’ve chosen whether to work with SpringMVC or Spring WebFlux, the next step is to choose a reactive server.

  • For Spring MVC, you need to make sure your selected Servlet container supports reactive meaning it has to be a Servlet 3.1+ container.

  • For Spring WebFlux, you also have the choice of running on a non-servlet reactive server such as Netty.

The difference between the two is that servlet container will use threads for your reactive application, a reactive server will use the event loop. This means that the reactive servers will use less threads.

Other decisions

Though choosing your reactive library and server are major decisions and may have deep impact on your performance, there are other key decisions that will affect your performance.

The use of reactive non-blocking methodologies is supposed to use less threads and resources, so when coding our application and choosing 3rd parties we need to remember that blocking actions may be hiding in there or even in plain-sight:

  • If you are using a 3rd party that supports reactive non-blocking actions, use an appropriate driver for it. For example, MongoDb and Couchbase, have Spring reactive support.

  • If you must invoke a blocked action, use the publishOn operator to process the action on a different thread.

Writing your reactive controller

Note: All code references refer to the Spring-webflux library.

Writing a reactive REST controller requires:

  • Enabling WebFlux in your application Spring Configuration, to import your WebFlux configuration
    @EnableWebFlux
    
  • Changing the return types of your REST controller to Mono and/or Flux
    @RestController
    @RequestMapping(value = "/person", produces = MediaType.APPLICATION_JSON_VALUE)
    public class PersonController {
    
      private final static Logger LOG = LoggerFactory.getLogger(PersonController.class);
    
      private final PersonService personService;
    
      @Autowired
      public PersonController(PersonService personService) {
          this.personService = personService;
      }
    
      @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
      public Flux<Person> postPersons(@Valid @RequestBody Flux<Person> persons) {
          return created = personService.storePersonsFlux(persons);
      }
    
      @GetMapping
      public Flux<Person> getAll() {
          return personService.getAll();
      }
    }
    

    Notice, how little your POJO has changed, but from this point your code will proceed with Mono/Flux, meaning in any actions you will need to work with it by sending it to a reactive service, and constructing reactive return types. Some out of the box services already support Mono/Flux, for example reactive Spring-Data libraries for MongoDb and Couchbase, and in some you will need to learn the Mono/Flux API to handle your objects.

But wait

WebFlux added a new way to create a reactive controller and it is functional (and quite niffty). Instead of annotating your POJO class, add a function annotated as a bean to your application context:

@Bean
public RouterFunction<ServerResponse> controller(PersonHandler handler) {
        return route(GET("/person/{id}").and(accept(APPLICATION_JSON)), handler::getPerson)
                .andRoute(GET("/person").and(accept(APPLICATION_JSON)), handler::listPeople)
                .andRoute(POST("/person"), handler::createPerson);
}
  • RouterFunction Routes requests according to the URL predicate to a HandlerFunction

  • ServerRequest Representing an HTTP request

  • ServerResponse Representing an HTTP response

  • HandlerFunction A function that receives a ServerRequest and returns a ServerResponse

Your PersonHandler implements the HandlerFunctions, so its interface would look like:

@Service
public interface PersonHandler {
    public <T extends ServerResponse> Mono<T> getPerson(ServerRequest serverRequest);

    public Mono<ServerResponse> listPeople(ServerRequest serverRequest);

    public Mono<ServerResponse> createPerson(ServerRequest serverRequest);
}

When writing your handler functions you have to note that both the ServerRequest and the ServerResponse are immutable, so to construct your response you will need the build method.

To summarize

Writing a reactive library requires you to learn the Mono and Flux API, but also choosing a library and a reactive server. I hope that laying out the stages to starting your reactive application, will enable you to use reactive programming in your Spring application.

Senior Java Developer

Backend Group
Thank you for your interest!

We will contact you as soon as possible.

Send us a message

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com