Reactive programming is gaining popularity due to its efficiency in handling asynchronous data streams. Micronaut, with its built-in support for reactive paradigms like RxJava and Reactor, provides a powerful and lightweight foundation for building non-blocking, event-driven applications.
In this post, we’ll explore how to work with Reactive Programming in Micronaut using RxJava and Reactor, understand concepts like Mono
, Flux
, and reactive flows, and write practical code examples using Maven.

What is Reactive Programming?
Reactive Programming is a declarative programming paradigm that centers around the concept of asynchronous data streams and the automatic propagation of changes through a system. Rather than relying on traditional, imperative methods of managing data and control flow, reactive programming emphasizes responding to events or data changes as they occur, enabling systems to be more flexible, responsive, and resilient.
In reactive systems, components communicate through observable data streams, which can emit values over time. When a value changes or a new event is emitted, all components or systems that are subscribed to that data stream are automatically notified and can react accordingly. This makes it easier to build applications that must deal with complex, dynamic data flows and high levels of concurrency.
Reactive programming is particularly beneficial for developing scalable and efficient applications, especially in environments that demand high responsiveness and the ability to handle a large number of simultaneous interactions. Common use cases include:
- REST APIs that need to support thousands of concurrent clients with minimal latency.
- Real-time data pipelines that continuously ingest, process, and distribute data from multiple sources.
- Microservices architectures, where services must interact asynchronously and remain loosely coupled while ensuring consistency and reliability.
By embracing asynchronous programming patterns and non-blocking operations, reactive programming helps developers create applications that are not only more performant and resource-efficient, but also easier to maintain and adapt to changing requirements over time.
Micronaut supports RxJava 2/3 and Project Reactor, giving developers flexibility in choosing the right library.
Micronaut Reactive Features
- Built-in support for RxJava and Reactor.
- Non-blocking I/O with Netty.
- Integration with HTTP Client/Server, MongoDB, Kafka, etc.
- Compile-time validation ensures reactive pipelines are optimized and efficient.
Project Setup with Maven
pom.xml
dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<dependencies> <dependency> <groupId>io.micronaut</groupId> <artifactId>micronaut-runtime</artifactId> </dependency> <dependency> <groupId>io.micronaut.rxjava3</groupId> <artifactId>micronaut-rxjava3</artifactId> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-core</artifactId> </dependency> </dependencies> |
Example with RxJava 3
Service Layer – GreetingService.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.kscodes.micronaut.advanced; import io.reactivex.rxjava3.core.Single; import jakarta.inject.Singleton; @Singleton public class GreetingService { public Single<String> getMessage(String name) { return Single.just("Hello, " + name + "! (from RxJava)"); } } |
Controller – GreetingController.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.kscodes.micronaut.advanced; import io.reactivex.rxjava3.core.Single; import io.micronaut.http.annotation.*; @Controller("/rx") public class GreetingController { private final GreetingService greetingService; public GreetingController(GreetingService greetingService) { this.greetingService = greetingService; } @Get("/{name}") public Single<String> greet(String name) { return greetingService.getMessage(name); } } |
Example with Reactor
Service Layer – ReactorGreetingService.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package com.kscodes.micronaut.advanced; import reactor.core.publisher.Mono; import jakarta.inject.Singleton; @Singleton public class ReactorGreetingService { public Mono<String> getMessage(String name) { return Mono.just("Hello, " + name + "! (from Reactor)"); } } |
Controller – ReactorGreetingController.java
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
package com.kscodes.micronaut.advanced; import reactor.core.publisher.Mono; import io.micronaut.http.annotation.*; @Controller("/reactor") public class ReactorGreetingController { private final ReactorGreetingService service; public ReactorGreetingController(ReactorGreetingService service) { this.service = service; } @Get("/{name}") public Mono<String> greet(String name) { return service.getMessage(name); } } |
Testing the Endpoints
You can test these endpoints using:
1 2 3 4 5 |
curl http://localhost:8080/rx/John curl http://localhost:8080/reactor/Jane |
Expected output:
1 2 3 4 5 |
Hello, John! (from RxJava) Hello, Jane! (from Reactor) |
When to Use RxJava vs Reactor?
- Use RxJava if you’re already familiar with it or migrating from legacy code.
- Use Reactor if you want tighter integration with Spring or prefer using Mono/Flux, which are better aligned with Micronaut’s reactive stack.
Conclusion
Reactive Programming with Micronaut using RxJava or Reactor allows you to build scalable, efficient applications with ease. By using non-blocking constructs and streaming APIs, you can handle thousands of requests concurrently with minimal resources.
Micronaut’s integration makes this process seamless and elegant. Whether you’re creating microservices or real-time applications, the reactive approach enhances performance and responsiveness.