Open In App

Spring Boot – Reactive Programming Using Spring Webflux Framework

Last Updated : 06 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we will explore React programming in Spring Boot, Reactive programming is an asynchronous, non-blocking programming paradigm for developing highly responsive applications that react to external stimuli.

What is Reactive Programming

  • In reactive programming, the flow of data is asynchronous through push-based publishers and subscribers instead of synchronous pull-based calls.
  • The core abstraction in reactive programming is the reactive stream which provides a standard way to work with asynchronous streams of data. The two primary reactive stream interfaces are Publisher and Subscriber.
  • Publishers push data to Subscribers asynchronously. Subscribers register callbacks and are notified when new data arrives instead of actively polling for it.
  • Examples of reactive streams include Mono and Flux in Spring Webflux. Mono represents a single event/value and Flux represents a stream of multiple values.

Benefits of Reactive Programming with Spring Webflux

  • Support for Reactive Types
  • Integration with Reactive Streams
  • Non-blocking I/O
  • Microservices-friendly

Spring Webflux Dependency

Gradle:

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-webflux'
}

Maven:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webflux -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
<version>6.1.3</version>
</dependency>

Reactive Types in Spring Webflux

  1. Mono: Mono specifically represents a single value or no value at all
  2. Flux: Flux represents a **stream of zero or more elements** emitted over time

Step By Step Implementation

Step 1: Set up a new Spring MVC project

Create a new Maven project in your preferred IDE (e.g., IntelliJ or Eclipse or Spring Tool Suite) and add the following dependencies.

  • Spring Webflux
  • Mongo Db – for Database
  • Lombok

XML




<?xml version="1.0" encoding="UTF-8"?>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>REST_Spring_Flux</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>REST_Spring_Flux</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</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.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.projectreactor</groupId>
            <artifactId>reactor-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
  
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>
  
</project>


Project Structure:

Directory Structure

Step 2: Configure Mongo Db Database

# MongoDB properties
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=student_management
  • host: host property pecifies the hostname or IP address of the MongoDB server. In this example we are using localhost.
  • port: property defines the port number on which the MongoDB server is running. In this example we are running our server on port no : 27010 [8080].
  • database: sets the name of the MongoDB database that our Spring Boot application will connect to. In this example, the database name is “student_management”.

Step 3: Create Model Class

Student.class File:

Java




package com.example.demo.entities;
  
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
  
@Document
public class Student {
    @Id private String id;
    private String name;
    private int age;
  
    public Student(String id, String name, int age)
    {
        super();
        this.id = id;
        this.name = name;
        this.age = age;
    }
  
    public Student()
    {
        super();
        // TODO Auto-generated constructor stub
    }
  
    public String getId() { return id; }
  
    public void setId(String id) { this.id = id; }
  
    public String getName() { return name; }
  
    public void setName(String name) { this.name = name; }
  
    public int getAge() { return age; }
  
    public void setAge(int age) { this.age = age; }
}


Note: @Document annotation indicate that this class should be mapped to a MongoDB document.

Step 4: Create Repository Interface

StudentRepository.class File:

Java




package com.example.demo.repositories;
  
import com.example.demo.entities.*;
import org.springframework.data.mongodb.repository.ReactiveMongoRepository;
  
public interface StudentRepository
    extends ReactiveMongoRepository<Student, String> {
}


Step 5: Create Controller

StudentController.class File:

Java




package com.example.demo.controller;
  
import com.example.demo.entities.Student;
import com.example.demo.services.StudentService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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
@RequestMapping("/api/students")
public class StudentController {
  
    private final StudentService studentService;
  
    public StudentController(StudentService studentService)
    {
        this.studentService = studentService;
    }
  
    public Mono<Student>
    saveStudent(@RequestBody Student student)
    {
        return studentService.saveStudent(student);
    }
  
    @GetMapping public Flux<Student> getAllStudents()
    {
        return studentService.getAllStudents();
    }
  
    @GetMapping("/{id}")
    public Mono<Student>
    getStudentById(@PathVariable String id)
    {
        return studentService.getStudentById(id);
    }
    @PostMapping
    public Mono<Student>
    createStudent(@RequestBody Student student)
    {
        return studentService.saveStudent(student);
    }
  
    @DeleteMapping("/{id}")
    public Mono<Void> deleteStudent(@PathVariable String id)
    {
        return studentService.deleteStudent(id);
    }
}


Step 6: Create Service Interface

StudentService.class File:

Java




package com.example.demo.services;
import com.example.demo.entities.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
public interface StudentService {
    Mono<Student> saveStudent(Student student);
    Flux<Student> getAllStudents();
    Mono<Student> getStudentById(String id);
    Mono<Void> deleteStudent(String id);
}


Step 7: Create ServiceImpl

StudentServiceImpl.class File:

Java




package com.example.demo.services;
  
import com.example.demo.entities.*;
import com.example.demo.repositories.StudentRepository;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
  
@Service
public class StudentServiceImpl implements StudentService {
  
    private final StudentRepository studentRepository;
  
    public StudentServiceImpl(
        StudentRepository studentRepository)
    {
        this.studentRepository = studentRepository;
    }
  
    @Override
    public Mono<Student> saveStudent(Student student)
    {
        return studentRepository.save(student);
    }
  
    @Override public Flux<Student> getAllStudents()
    {
        return studentRepository.findAll();
    }
  
    @Override public Mono<Student> getStudentById(String id)
    {
        return studentRepository.findById(id);
    }
  
    @Override public Mono<Void> deleteStudent(String id)
    {
        return studentRepository.deleteById(id);
    }
}


Step 8: Run the Application

Now, You can run the Spring Boot application from IDE or by using the command-line tool provided by Spring Boot.

mvn spring-boot:run

Step 9: Test the Endpoints Using Postman

POST: http://localhost:8080/api/students-- Post the student data
GET: http://localhost:8080/api/students-- Get all student details
GET: http://localhost:8080/api/students/{id} -- Get the student details by Id

Output:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads