How to implement Reactive Programming in Spring Boot?

Programming comes in different paradigms.

For long , we did procedural programming using languages like C where the business logic was executed step by step in a procedural manner.

Then came Object Oriented Programming where you modeled your business requirement into domain objects. It represented real world more closely and has been quite successful even now.

And we also have Functional programming , Event Driven programming etc.

The latest among these is Reactive Programming.

What is this?

Let’s dive into it.

Contents:

  1. Reactive programming – definition
  2. Reactive programming in Spring Boot
  3. How to create a reactive REST API – demo
  4. How to consume a reactive REST API – demo
  5. Backpressure
  6. Conclusion

1.Reactive Programming – definition

Let’s consider the traditional way we write REST APIs to return JSONs.

You create a REST API through @RestController and @RequestMapping annotations and return a Java object which is automatically converted to a JSON object by Spring .

When you consume these APIs using a Spring library like RestTemplate you get some data back in a single shot.

And also your call is blocking.

Until you finish consuming the API response you can’t execute any other piece of code.

Also it is synchronous , the call is executed by the same thread which makes the call.

So in short , traditional programming (also called imperative programming) is :

blocking, synchronous and deals with single data.

On the otherhand, reactive programming is used :

When you deal with data streams.

Data streams are continuous flow of data.

Let’s say you call a REST API and it keeps sending new data and you keep consuming it as long as it sends.

In imperative programming , to get multiple data you need to make multiple calls.

But in reactive programming you can make a single call to get multiple continuous data (data streams)

Also reactive calls are non blocking.

You can call a REST API and proceed with executing your subsequent lines of code.

You can get your data by subscribing to the data streams in a different thread.

And,

Reactive programming is asynchronous.

The thread which invokes the REST API hands over the execution to another thread.

But wait!

what is the difference between non blocking and asynchronous?

They both sound the same.

The major difference is when you say asynchronous , the processing is handled by a different thread in the background and you can retrieve the final result only when the complete result is available and fetching the final result is blocking (example Future.get() method in java).

Whereas when you say non blocking , you can get partial data whatever is available at the time. You don’t have to block the current thread to get the full data.

Also you can control how much data and at what rate you want to receive data in reactive programming.

This is called backpressure.

You want to receive only 10 sets of data at a time? You can.

You want to receive only the first 5 sets of data? You can.

You want to delay the time you receive two different sets of data so that the consumer API is not overwhelmed? You can.

In short ,

Reactive programming is non blocking, asynchronous and deals with data streams not single data and also supports backpressure.

2.Reactive Programming in Spring Boot

Spring supports reactive programming using “Project Reactor” , a platform which supports reactive programming. It provides Spring Webflux library to write reactive REST APIs and Spring WebClient library to consume reactive REST APIs.

Unlike traditional REST APIs reactive REST APIs return only two type of objects:

  1. Mono
  2. Flux

All java objects are wrapped with these reactive objects.

Mono represents a single stream of data.

Flux represents multiple streams of data.

So you either return a single stream of data or multiple streams of data.

For example ,

Mono<String> means the REST API returns a single string value.

Flux<String> means the REST API returns multiple strings in streams. This sounds similar to List<String> but unlike List which is returned completely in a single shot , Flux data can be returned in batches or with delay (eg) every 2 seconds return a String) or in specific amounts ( eg) only return the first 10 string values).

Let’s get into some examples to understand them in a better way.

3.How to create a reactive REST API – demo

Now that we have seen what is reactive programming , let’s try to implement a use case in Spring Boot.

Let’s create a reactive REST API which emits stream of data.

For this to work , you need to add reactive dependences.

Add spring-boot-starter-webflux for creating reactive REST APIs and

spring-boot-starter-data-mongodb-reactive for creating reactive databases.

To fully utilize the advantages of reactive programming your entire technology stack should be reactive:

REST APIs should be reactive

The database should be reactive

If you consume other REST APIs they should also be reactive

So we will use reactive mongodb as a dependency.

Here is the entire pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.0</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>reactivespring</artifactId>
	<version>1.0.0</version>
	<name>reactivespring</name>
	<description>Demo project for Spring Reactive Programming</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<dependencies>
	
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-mongodb-reactive</artifactId>
		</dependency>
		
		 
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-webflux</artifactId>
		</dependency>

		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

I have also added lombok to reduce boiler plate code.

I installed Mongodb in my local and added the configuration in application.yml:

spring:
  data:
    mongodb:
      host: localhost
      port: 27017
      database: reactivedb

Spring will now automatically connect to the local Mongodb instance.

I created two reactive REST APIs one to add a collection and another to retrieve all elements in the collection.

Let’s say you want to store a collection of superheroes in your database.

Here is the REST API to add a superhero:

	@PostMapping("/superhero")
	public Mono<Superhero> addSuperHero(@RequestBody Superhero hero) {

		return repo.save(hero);

	}

As you see the return type is a “Mono” object which represents a single stream of data.

Its not much different from returning a SuperHero object. The difference is move obvious when you use “Flux” object as in the second example below.

Here is the REST API to fetch all superheroes:

	@RequestMapping(value = "/superhero", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<Superhero> getSuperHero() {

		
		return repo.findAll().delayElements(Duration.ofSeconds(3));

	}

Notice that the return type is a “Flux” object here.

Instead of returning a list of superheroes we are returning a flux of super heroes.

And we are also introducing a delay of 3 seconds between each stream of data . This is called backpressure and is one of the ways to reduce load on the consumer. Since the repository we use is also reactive we are able to do this easily through the library method.

Also notice the produces element in @RequestMapping annotation. It does not return a JSON as we do in traditional REST APIs. For reactive programming to work you need to return streams. Hence we are returning a text stream here.

Here is the entire REST Controller class:

package com.example.reactive;

import java.time.Duration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@RestController
public class ReactiveController {

	@Autowired
	private ReactiveRepository repo;

	@RequestMapping(value = "/superhero", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
	public Flux<Superhero> getSuperHero() {

		
		return repo.findAll().delayElements(Duration.ofSeconds(3));

	}

	@PostMapping("/superhero")
	public Mono<Superhero> addSuperHero(@RequestBody Superhero hero) {

		return repo.save(hero);

	}
}

And here is the reactive repository:

package com.example.reactive;

import org.springframework.data.mongodb.repository.ReactiveMongoRepository;

public interface ReactiveRepository extends ReactiveMongoRepository<Superhero, String> {

}

It is very much similar to traditional Spring Data repositories except that we extend ReactiveMongoRepository here.

Here is the SuperHero domain class:

package com.example.reactive;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import lombok.Builder;
import lombok.Data;

@Document
@Data
@Builder
public class Superhero {

	
	@Id
	private String id;
	
	private String name;
	
	private int age;
}

That’s it.

Now let’s run the application and add some superheroes.

I added a Superman and Spiderman as well.

Now let’s retrieve all the superheroes.

Notice that if you use postman to retrieve all the superheroes they will be returned in a single shot as postman has a blocking API.

You can try through your browser instead and you will notice that you get each of the 3 superheroes after a delay of 3 seconds:

Here is a video clipping of the same:

Unlike a list of data which can be returning only as a single set of data , in reactive programming you can get data in multiple streams in the way you need it .

Now let’s consume the above reactive REST API in a reactive way.

4.How to consume a reactive REST API – demo

You can’t possibly use Spring REST Template to consume a reactive REST API because it is blocking. Even if you can use , you forego the advantage of reactive programming.

Spring provides Spring WebClient library to consume reactive APIs in a reactive way (asynchronous, non blocking).

Here is an example REST client which does this and gets the list of super heroes which we added in the previous example.

	public void test() {

		Flux<Map> response = WebClient
							.builder()
							.baseUrl("http://localhost:8088/superhero")
							.build()
							.get()
							.retrieve()
							.bodyToFlux(Map.class);

		response.subscribe(

				data -> {

					System.out.println(data);
				});

	}

We build a WebClient using builder pattern in a fluent style in the above example and convert the response body to Flux data type.

And then you subscribe to the Flux data stream and print data in a different thread (asynchronous)

Again here data will be retrieved every 3 seconds and printed in the console.

I deployed the above piece of code in a rest API to test the same:

package com.example.reactive;

import java.util.Map;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Flux;

@RestController
public class WebClientTestController {

	@GetMapping("/reactiveclient")
	public void test() {

		Flux<Map> response = WebClient
							.builder()
							.baseUrl("http://localhost:8088/superhero")
							.build()
							.get()
							.retrieve()
							.bodyToFlux(Map.class);

		response.subscribe(

				data -> {

					System.out.println(data);
				});

	}

}

And then started the client app and hit the test API:

As you notice , unlike consuming a non reactive REST API , using Spring WebClient you can consume data in sequence with a time interval!

5.Backpressure

Backpressure as already discussed is one of the key features of reactive programming.

Instead of dealing with huge data at once and overloading your servers you can control how you want to fetch data using backpressure.

In the previous example we employed one of the backpressure techniques , pushing data to your consumer with a time interval.

There are various other backpressure techniques too:

Fetching only first ‘x’ amount of data:

You can do this using take() method:

		response.take(2).subscribe(

				data -> {

					System.out.println(data);
				});

The above code will fetch only first 2 superheroes.

Fetching data only for specific time period:

You can use the same overloaded take() method and indicate that you need to fetch data only for the given time period.

		response.take(Duration.ofSeconds(5)).subscribe(

				data -> {

					System.out.println(data);
				});

The above code will fetch superheroes only for 5 seconds. After that whatever data is sent by the publisher will be ignored.

In addition you can cancel receiving data abruptly in the middle using cancel() method, limit the rate at which data is received using limitRate() method.

Backpressure techniques can be employed both at the publisher end and the subscriber end.

6. Conclusion:

Reactive programming is a paradigm shift.

It improves the performance of your application as users need not be blocked for every request.

Similarly it improves the responsiveness of your application which improves user experience.

It improves resilience of your application as backpressure prevents your application from being overloaded with data.

It improves concurrency as reactive programming can handle multiple concurrent requests with fewer microservice instances.

But traditional imperative programming works well for a lot of use cases.

If you are just dealing with data and not data streams , then imperative programming works as fine as reactive programming.

Also reactive application is more suitable for event driven applications than CRUD applications and hence imperative programming could be chosen for the later.

That’s it!

You can also buy an ebook version of this post (along with how to call reactive APIs from javascript) here:

https://gumroad.com/js/gumroad-embed.js

Here is the code:

https://github.com/vijaysrj/reactivespring

https://github.com/vijaysrj/reactivewebclient

Comments

4 responses to “How to implement Reactive Programming in Spring Boot?”

  1.  Avatar
    Anonymous

    Very well explained in detail with example of when to use and when not to use Reactive Programming. The code and demo is super helpful. Thanks.

    1. Vijay SRJ Avatar
      Vijay SRJ

      Thank you very much for providing feedback !

  2. Jawahar Avatar
    Jawahar

    Excellent Explanation. Couldn’t have been better. Keep doing such content.

    1. Vijay SRJ Avatar
      Vijay SRJ

      thank you very much Jawahar 🙂

Leave a Reply to JawaharCancel reply

Discover more from The Full Stack Developer

Subscribe now to keep reading and get access to the full archive.

Continue reading