Reactive programming is a developer paradigm focused on creating applications that are responsive to changes, asynchronous in nature, and driven by events. It emphasizes handling data streams and events as first-class citizens, enabling developers to write more efficient, scalable, and resilient code. Java reactive programming is a programming approach that emphasizes the development of applications that are both responsive and scalable, capable of handling both concurrent and asynchronous operations effectively.
Terms need to know:
Producer:The producer acts as a data source and it will publish events.
Subscriber: It listens to the events from the producer, it subscribes and consumes those events.
Processor: It acts as a middleman that connects publisher to subscriber.
Stream: It is a series of events that are ordered in time. A stream can emit three different types of signals: A value of a certain type, an error, or a completed signal.
Reactive Streams: A standard for asynchronous stream processing with non-blocking backpressure.
Flux and Mono: Specific types of observables provided by Project Reactor for handling streams of data. Flux represents a stream of multiple items, while Mono represents a stream of at most one item.
Backpressure: The mechanism used to handle situations where the rate of data production exceeds the rate of data consumption.
Asynchronous Data Stream: A stream of data that emits values one at a time with a delay between them is known as an asynchronous data stream.
Core features of Reactive Programming:
- New programming Paradigm
- Asynchronous and non-blocking
- Functional style code
- Data flow as event driven Stream
- Backpressure on data streams
Why we required Reactive Programming :
Inherently Lazy Execution: Reactive programming promotes laziness, meaning computations don’t occur until there’s a subscriber. This “stop & play” capability allows for more efficient resource utilization and responsive applications.
Concise Code: By focusing on modelling events and their dependencies, reactive programming often results in more compact implementations. Developers spend less time on implementation details and more on understanding the overall flow of events.
Less Code To Write: With libraries like RxJS providing built-in operators for common behaviours (e.g., debouncing, throttling), developers spend less time implementing these functionalities from scratch. This leads to reduced development time and more maintainable codebases.
Effortless Cancellation: Reactive programming simplifies cancellation mechanisms, making it easy to cancel on going operations. This capability is particularly useful in scenarios where users need to abort or change their requests or actions.
How Reactive Programming working with Java:
In Java, reactive programming is often implemented using libraries such as Reactive Streams, Project Reactor, and RxJava, which provide APIs for writing reactive code. These libraries allow developers to handle streams of data and events asynchronously, using concepts such as Observables, Observers, and Streams, and applying operators for processing and transforming data in a reactive and non-blocking manner.
Project Reactor: Developed by the Spring team, Project Reactor is a reactive programming library for building non-blocking applications on the JVM. It provides support for reactive streams, asynchronous operations, and reactive data processing.
RxJava: RxJava is a reactive extension library for Java that implements the ReactiveX API. It allows developers to work with asynchronous data streams and provides operators for composing and transforming streams of data in a declarative and functional style.
Example:
Basic Crud operation using Java Reactive programming:
Entity:
@Table("products") public class Product { @Id private Long id; private String name; private String description; private double value; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public double getValue() { return value; } public void setValue(double value) { this.value = value; } public Product() { super(); } public Product(Long id, String name, String description, double value) { super(); this.id = id; this.name = name; this.description = description; this.value = value; } }
Controller:
@RestController public class ProductController { @Autowired ProductService productService; @GetMapping("/allproducts") public Flux getAllProducts() { return productService.getAllProducts(); } @GetMapping("/getproductbyid/{id}") public Mono getProductById(@PathVariable Long id) { return productService.getProductById(id); } @DeleteMapping("/deleteproductbyid{id}") public Mono deleteProductById(@PathVariable Long id) { return productService.deleteProduct(id); } @PostMapping("/saveproduct") public Mono saveProduct(@RequestBody Product product) { return productService.saveProduct(product); } }
Repository:
import org.springframework.data.repository.reactive.ReactiveCrudRepository; public interface ProductRepository extends ReactiveCrudRepository<product, long=""> { } </product,>
Service:
@Service public class ProductService { @Autowired ProductRepository productRepository; public Flux getAllProducts() { return productRepository.findAll(); } public Mono getProductById(Long id) { return productRepository.findById(id); } public Mono deleteProduct(Long id) { return productRepository.deleteById(id); } public Mono saveProduct(Product product) { product.setId(null); return productRepository.save(product); } }
Pom.xml:
Application.properties:
spring.r2dbc.url=r2dbc:mysql://localhost:3306/reactive spring.r2dbc.username=root spring.r2dbc.password=root logging.level.org.springframework.data.repository=DEBUG logging.level.org.springframework.r2dbc.core=DEBUG
Output:
Steps:
Step 1: Add required dependencies in pom.xml file.
Step 2: Create a product entity with required fields.
Step 3: Create a ProductRepository by extending ReactiveCrudRepository.
Step 4: Create a ProductService and manage operations related to products.
Step 5: Create a ProductController to handle client request related to products.
Step 6: Configure the properties file for Database connectivity.
Higly usage area’s of Reactive programming:
Web Development: Java reactive programming is a great approach when you aim to build websites that need to work with asynchronous, non-blocking, and concurrent requests.
IoT(Internet of things): Reactive programming is a great tool for handling all the data streams from IoT devices. Since data generated from IoT devices is large, the responsive and flexible character of reactive programming makes it suitable for handling it.
Mobile Development: Mobile app development, particularly for real-time applications and games, benefits from reactive programming. Libraries such as RxJava for Android and RxSwift for iOS enable developers to handle asynchronous tasks, manage data streams, and create responsive user experiences.
Conclusion:
Java reactive programming is a great tool for building robust, scalable, and responsive modern applications. It is natural for developers to experiment with new programming paradigms and strive for further development.