Reactive Stream With Spring Boot

Sivaram Rasathurai
3 min readMay 16, 2021
Photo by Cam Adams on Unsplash

Reactive Stream is a specification for asynchronous stream processing.

In other words, a system where lots of events are being produced and consumed asynchronously. In order for an application to be reactive, the first thing it must be able to do is to produce a stream of data. Reactive Core gives us two data types that enable us to do this.

FLUX

The first way of doing this is with a Flux. It’s a stream that can emit 0..n elements. Let’s try creating a simple one: Flux<String> just = Flux.just("1", "2", "3"); In this case, we have a static stream of three elements.

Mono

The second way of doing this is with a Mono, which is a stream of 0..1 elements. Let’s try instantiating one: Mono<String> just = Mono.just("foo");
This looks and behaves almost exactly the same as the Flux, only this time we are limited to no more than one element.

First, it should be noted that both Flux and Mono are implementations of the Reactive Streams Publisher interface. Both classes are compliant with the specification, and we could use this interface in their place

Subscribing to a Stream

Now we have a high-level overview of how to produce a stream of data, we need to subscribe to it in order for it to emit the elements.

Collecting Elements

Let’s use the subscribe() method to collect all the elements in a stream:

List<Integer> elements = new ArrayList<>();
Flux.just(1, 2, 3, 4).log().subscribe(elements::add);

The data won’t start flowing until we subscribe. Notice that we have added some logging as well, this will be helpful when we look at what’s happening behind the scenes.

Comparison to Java 8 Streams

It still might appear that we have something synonymous to a Java 8 Stream doing collect:

List<Integer> collected = Stream.of(1, 2, 3, 4).collect(toList());

Only we don’t.

The core difference is that Reactive is a push model, whereas the Java 8 Streams are a pull model. In reactive approach. events are pushed to the subscribers as they come in.

The next thing to notice is a Streams terminal operator is just that, terminal, pulling all the data and returning a result. With Reactive we could have an infinite stream coming in from an external resource, with multiple subscribers attached and removed on an ad hoc basis. We can also do things like combine streams, throttle streams and apply backpressure, which we will cover next.

Backpressure

The next thing we should consider is backpressure. In our example, the subscriber is telling the producer to push every single element at once. This could end up becoming overwhelming for the subscriber, consuming all of its resources.

Backpressure is when a downstream can tell an upstream to send it fewer data in order to prevent it from being overwhelmed.

Operating on a Stream

We can also perform operations on the data in our stream, responding to events as we see fit.

Mapping Data in a Stream

A simple operation that we can perform is applying a transformation. In this case, let’s just double all the numbers in our stream:

Flux.just(1, 2, 3, 4).map(i -> i * 2).subscribe(elements::add);

map() will be applied when onNext() is called.

Thanks for reading this Blog!!! Hope you will enjoy it.
Leave a comment below or ask me via Twitter if you have any questions.

--

--