Reactive has definitely become a trending word in software development over the past few years, in part because of the high growth of internet users and the corresponding need to create more scalable applications. Some people might say that reactive programming is a hard subject to learn, but certain frameworks and libraries are making it easier to implement even without a deep understanding of how it works.
I believe that learning through assimilation is a great way to understand how things work, so today, we'll show you how to write a REST web service using reactive programming with Spring Web Flux as an alternative to Spring Web MVC. The goal is to demonstrate to developers who are used to using Spring MVC that it's possible and highly beneficial to migrate to a reactive application by implementing very small and simple changes.
Before we begin, it's important to explain what reactive programming means. Phrased succinctly, reactive programming is a programming paradigm oriented toward data streams and the propagation of changes (i.e., it's asynchronous).
An easy way to understand the propagation of changes is to remember how an excel formula works: every time one of its referred cells is changed, the value is updated. This behavior resembles the design pattern Observer introduced in the famous "Gang of Four" book, Design Patterns: Elements of Reusable Object-Oriented Software.
Image courtesy of upload.wikimedia
In the picture above, we can see that the Subject possesses information that is being watched by the Observers. These observers register themselves to receive notifications when the Subject suffers a change of state. Once notified, the Observers perform some operation for which they have been programmed. That is when the propagation of changes happens.
When talking about reactive programming, there are some essential features we ought to define:
- Data Streams: sequences of events ordered temporally that can be manifested in several ways, e.g. as parts of a file being downloaded, as mouse cursor positions, as Twitter feeds, as RESTful service calls, etc.
- Asynchronous: events are captured asynchronously; a function is defined to be performed when one event is issued, another to when an error is issued, and another to when a completion event is issued.
- Non-blocking: a blocking code will stop and wait for more data (disk read, network, etc.), but the non-blocking code will process the available data, request to be notified when more data is available, and then continue.
- Backpressure: the subscriber's ability to limit data
- Failures as Messages: exceptions should not be thrown in the traditional way. In fact, they must be processed by a handler function.
Reactive programming is built upon four pillars:
- Responsive: A responsive system is quick to react to all users — under blue skies and grey skies — in order to ensure a consistently positive user experience.
- Resilient: A resilient system applies proper design and architecture principles to ensure responsiveness in any scenario.
- Scalable: A scalable system is easily upgraded on demand to ensure responsiveness under various load conditions.
- Message-driven: A message-driven application may be event-driven, actor-based (directed messages), or a combination of the two. The main difference between messages and events is that messages are directed while events happen. Messages have a clear destination while events may be observed by zero or more (0-N) Observers.
Reactive Streams API
Spring Framework 5 introduces the React Streams API to create a pattern for processing streams asynchronously with non-blocking return pressure. Reactive Streams was started in 2013 by engineers from Netflix, Pivotal, Lightbend (formerly Typesafe), Red Hat, Twitter and Oracle. The Reactive Streams API defines 4 interfaces: Publisher, Subscriber, Subscription and Processor.
Spring WebFlux is the support module for reactive programming in the Spring Framework's web layer. One of the most interesting things about this module is that even though the architecture behind it is quite different from the conventional Spring MVC, it can be used as an alternative to Spring MVC by utilizing some of the most relevant Spring MVC features: the annotations @Controller and @RequestMapping. We can see this in the following image:
Spring Reactive Types
Spring Framework 5 uses Reactor - a Reactive Stream implementation - to provide two Reactive Streams Publishers called Mono and Flux. The first of these is responsible for managing operations in data sequences of 0..1, and the second manages operations in data sequences of 0..N. These publishers are exposed in many of Spring Framework's own APIs, but it also provides full support for using RxJava at the application level.
Now let's look at the differences between a REST CRUD service implemented with Spring MVC and one implemented with Spring WebFlux. In order to show the difference, we are going to walk through implementing three layers in each module: Repository, Service and Controller.
|Spring MVC:||Spring WebFlux:|
The difference here is merely extending from ReactiveMongoRepository instead of MongoRepository.
|Spring MVC:||Spring WebFlux:|
Here we can see some small differences. For instance, instead of using Person object, we change to Mono<Person>, and we can also change List<Person> to Flux<Person>. Beyond this, in the Service save method, we needed to call block() method in the Mono<Person> parameter to convert the stream into an object, since the ReactiveMongoRepository<Person, String> save method expects us to pass a Person object. That's how we ask the data stream to perform a blocking action and give us the object to be saved.
|Spring MVC:||Spring WebFlux:|
Similarly to the changes we made in the service layer, here we need to replace Person with Mono<Person> and List<Person> with Flux<Person>.
In this post, we discussed a little bit about what reactive programming is and saw that very few changes are required to migrate from Spring MVC to Spring WebFlux. If you are not convinced yet about why you should consider using Spring WebFlux and reactive programming, here are some benefits: it's simpler than regular threading; leads to code are easier to understand, test and debug; it makes the code more maintainable; concurrency handling is hassle-free and composing asynchronous operations is straight forward. You can learn more about its benefits here.
Of course, not everything is perfect--you might have to be careful to not create memory leaks, and you probably will need to change the way you think to actually understand how to solve problems using reactive programming, but I think starting with Spring WebFlux can be a good way to start understanding reactive programming.
If you'd like to see the full project from both services, you can take a look here.
Fernando Tavares is a Java Engineer at Avenue Code who works mostly developing microservices but every now and then flips the hat and acts as a UI Engineer working with VueJS applications.