top of page
Search

Implementing a Reactive Framework with Spring WebFlux and Java

  • Writer: Rajkishore R
    Rajkishore R
  • Mar 8
  • 4 min read

Spring WebFlux is a reactive programming framework introduced in Spring 5, enabling non-blocking, asynchronous processing. It is built on Project Reactor, providing support for Mono (0-1 element) and Flux (0-N elements). Below is a step-by-step guide to implementing a reactive framework using Spring WebFlux in Java.


1. Project Setup

Use Spring Initializr (https://start.spring.io/) and select:

  • Spring Boot Version: The latest stable version

  • Dependencies:

    • Spring Reactive Web

    • Spring Boot DevTools

    • Lombok (optional)

    • Spring Data R2DBC (for reactive database access, if required)

2. Define the Reactive Model (Entity)

Example: Employee Entity

import lombok.AllArgsConstructor;

import lombok.Data;

import lombok.NoArgsConstructor;

import org.springframework.data.annotation.Id;

import org.springframework.data.relational.core.mapping.Table;


@Data

@NoArgsConstructor

@AllArgsConstructor

@Table("employees") // If using R2DBC

public class Employee {

@Id

private String id;

private String name;

private double salary;

}


3. Create a Reactive Repository

Spring Data provides ReactiveCrudRepository for non-blocking database operations.

import org.springframework.data.repository.reactive.ReactiveCrudRepository;

import reactor.core.publisher.Flux;


public interface EmployeeRepository extends ReactiveCrudRepository<Employee, String> {

Flux<Employee> findBySalaryGreaterThan(double salary);

}


4. Implement the Reactive Service

import org.springframework.stereotype.Service;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;


@Service

public class EmployeeService {

private final EmployeeRepository repository;


public EmployeeService(EmployeeRepository repository) {

this.repository = repository;

}


public Mono<Employee> getEmployeeById(String id) {

return repository.findById(id);

}


public Flux<Employee> getAllEmployees() {

return repository.findAll();

}


public Mono<Employee> saveEmployee(Employee employee) {

return repository.save(employee);

}


public Mono<Void> deleteEmployee(String id) {

return repository.deleteById(id);

}


public Flux<Employee> getHighSalaryEmployees(double minSalary) {

return repository.findBySalaryGreaterThan(minSalary);

}

}


5. Create a Reactive REST Controller

import org.springframework.web.bind.annotation.*;

import reactor.core.publisher.Flux;

import reactor.core.publisher.Mono;


@RestController

@RequestMapping("/employees")

public class EmployeeController {

private final EmployeeService service;


public EmployeeController(EmployeeService service) {

this.service = service;

}


@GetMapping("/{id}")

public Mono<Employee> getEmployee(@PathVariable String id) {

return service.getEmployeeById(id);

}


@GetMapping

public Flux<Employee> getAllEmployees() {

return service.getAllEmployees();

}


@PostMapping

public Mono<Employee> addEmployee(@RequestBody Employee employee) {

return service.saveEmployee(employee);

}


@DeleteMapping("/{id}")

public Mono<Void> deleteEmployee(@PathVariable String id) {

return service.deleteEmployee(id);

}

}


6. Reactive Database Configuration (Optional - R2DBC)

If using R2DBC for a reactive database like PostgreSQL or MongoDB:


spring.r2dbc.url=r2dbc:postgresql://localhost:5432/mydb

spring.r2dbc.username=postgres

spring.r2dbc.password=secret


Configure R2dbcConfig.java if needed:

import io.r2dbc.spi.ConnectionFactory;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.data.r2dbc.config.AbstractR2dbcConfiguration;


@Configuration

public class R2dbcConfig extends AbstractR2dbcConfiguration {

@Override

@Bean

public ConnectionFactory connectionFactory() {

return ConnectionFactoryOptions.builder()

.option(DRIVER, "postgresql")

.option(HOST, "localhost")

.option(PORT, 5432)

.option(USER, "postgres")

.option(PASSWORD, "secret")

.option(DATABASE, "mydb")

.build();

}

}


7. Testing with WebClient

Spring provides WebClient to make reactive HTTP calls.


import org.springframework.web.reactive.function.client.WebClient;

import reactor.core.publisher.Mono;


public class WebClientExample {

public static void main(String[] args) {

WebClient webClient = WebClient.create("http://localhost:8080");


Mono<String> response = webClient.get()

.uri("/employees")

.retrieve()

.bodyToMono(String.class);


response.subscribe(System.out::println);

}

}


8. Running the Application

  1. Start a PostgreSQL or MongoDB database if using R2DBC.

  2. Run the Spring Boot application:

    mvn spring-boot:run

  3. Test API using Postman or curl:

    curl -X GET http://localhost:8080/employees


    Key Features of WebFlux:

    Non-blocking, event-driven architecture

    Scalable for high-concurrency applications

    Backpressure handling using Mono & Flux

    WebClient for making asynchronous API calls

    Integration with R2DBC for reactive databases

    This implementation ensures an entirely reactive and non-blocking Spring Boot application using Spring WebFlux.



✅ Pros (Advantages)

1️⃣ Non-Blocking & High Performance

  • Handles thousands of concurrent requests without blocking threads.

  • Ideal for high-throughput applications (e.g., streaming, microservices).

2️⃣ Efficient Resource Utilization

  • Uses event-driven architecture to reduce CPU and memory usage.

  • Supports backpressure handling (prevents overwhelming consumers).

3️⃣ Scalability

  • Better suited for distributed, cloud-native applications.

  • Works well with microservices, Kubernetes, and serverless architectures.

4️⃣ Seamless Integration

  • Works with R2DBC (Reactive Database) instead of traditional JDBC.

  • Supports WebClient for non-blocking HTTP calls.

  • Easy integration with Kafka, RabbitMQ, and WebSockets.

5️⃣ Reactive Streams Compliance

  • Supports Project Reactor (Flux, Mono) for declarative data flow.

  • Compatible with RxJava, Akka Streams, and other reactive libraries.

6️⃣ Better for Real-Time Applications

  • Suitable for applications requiring real-time updates (e.g., chat apps, stock trading, IoT).

❌ Cons (Disadvantages)

1️⃣ Complex Debugging & Error Handling

  • Harder to trace errors due to asynchronous execution.

  • Stack traces can be difficult to follow in deeply nested reactive chains.

2️⃣ Steep Learning Curve

  • Requires understanding of reactive programming concepts (e.g., Flux, Mono, backpressure).

  • Developers need to unlearn imperative programming.

3️⃣ Limited Database Support

  • Traditional JDBC (blocking) is incompatible, requiring R2DBC or NoSQL databases.

  • Not all databases have full R2DBC support, limiting choices.

4️⃣ Higher Latency for Simple Use Cases

  • Extra complexity for simple CRUD operations (better handled by Spring MVC).

  • Higher response time if most interactions are already blocking.

5️⃣ Not Always Required

  • If the application doesn't have high concurrency or streaming needs, WebFlux is overkill.

  • Spring MVC (blocking) is still sufficient for many enterprise applications.

🆚 When to Use WebFlux vs. Traditional Spring MVC

Use Case

Spring WebFlux (Reactive)

Spring MVC (Blocking)

High concurrency (thousands of requests/sec)

✅ Yes

❌ No

REST APIs with simple CRUD

❌ No

✅ Yes

Streaming, chat, WebSockets

✅ Yes

❌ No

Integration with Kafka, RabbitMQ

✅ Yes

❌ No

CPU-bound operations (batch processing, ML)

❌ No

✅ Yes

Debugging & Maintainability

❌ Harder

✅ Easier

🔎 Final Verdict

✔ Choose Spring WebFlux when:

✅ You need high concurrency and scalability.

✅ Your application involves real-time streaming (chat, stock data, IoT).

✅ You are integrating with Kafka, WebSockets, or event-driven systems.

❌ Avoid Spring WebFlux when:

❌ You have traditional relational databases (JDBC-based).

❌ Your app has simple CRUD operations (use Spring MVC instead).

❌ You need easy debugging and maintainability.

 
 
 

Comments


bottom of page