41,99 €
This book will teach you how to build robust asynchronous and event-driven applications with ease.
This book targets existing Java developers who want to understand Reactive programming and build responsive and resilient asynchronous applications using Reactive stream implementations.
Reactive programming is an asynchronous programming model that helps you tackle the essential complexity that comes with writing such applications.
Using Reactive programming to start building applications is not immediately intuitive to a developer who has been writing programs in the imperative paradigm. To tackle the essential complexity, Reactive programming uses declarative and functional paradigms to build programs. This book sets out to make the paradigm shift easy.
This book begins by explaining what Reactive programming is, the Reactive manifesto, and the Reactive Streams specifi cation. It uses Java 9 to introduce the declarative and functional paradigm, which is necessary to write programs in the Reactive style. It explains Java 9's Flow API, an adoption of the Reactive Streams specifi cation. From this point on, it focuses on RxJava 2.0, covering topics such as creating, transforming,fi ltering, combining, and testing Observables. It discusses how to use Java's popular framework, Spring, to build event-driven, Reactive applications. You will also learn how to implement resiliency patterns using Hystrix. By the end, you will be fully equipped with the tools and techniques needed to implement robust, event-driven, Reactive applications.
This book is a tutorial about Reactive programming in Java using APIs as well as the RxJava library. Packed with a lot of well-described examples, it explains Reactive programming concepts in plain and readable language.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 431
Veröffentlichungsjahr: 2017
BIRMINGHAM - MUMBAI
Copyright © 2017 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.
Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.
First published: September 2017
Production reference: 1190917
ISBN 978-1-78712-423-3
www.packtpub.com
Author
Tejaswini Mandar Jog
Copy Editor
Safis Editing
Reviewer
Jay Lee
Project Coordinator
Prajakta Naik
Commissioning Editor
Aaron Lazar
Proofreader
Safis Editing
Acquisition Editor
Karan Sadawana
Indexer
Francy Puthiry
Content Development Editor
Lawrence Veigas
Production Coordinator
Nilesh Mohite
Technical Editor
Tiksha Sarang
Tejaswini Mandar Jog is a passionate and enthusiastic Java trainer. She has more than nine years of experience in the IT training field, specializing in Java, J2EE, Spring, and relevant technologies. She has worked with many renowned corporate companies on training and skill enhancement programs. She is also involved in the development of projects using Java, Spring, and Hibernate. Tejaswini has written two books. In her first book, Learning Modular Java Programming, the reader explores the power of modular programming to build applications with Java and Spring. The second book, Learning Spring 5.0, explores building an application using the Spring 5.0 framework with the latest modules such as WebFlux for dealing with reactive programming.
Jay Lee is currently working at Pivotal as senior platform architect. His job is to help big enterprise Cloud-Native Journey with Spring, Spring Boot, Spring Cloud, and Cloud Foundry. Before joining Pivotal, he spent 10 years at Oracle and worked with big enterprises for their large-scale Java distributed system and middleware. Currently, Jay is authoring a microservices book (the name of the book is yet to be decided) using Spring Boot and Spring Cloud.
For support files and downloads related to your book, please visit www.PacktPub.com.
Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.
At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.
https://www.packtpub.com/mapt
Get the most in-demand software skills with Mapt. Mapt gives you full access to all Packt books and video courses, as well as industry-leading tools to help you plan your personal development and advance your career.
Fully searchable across every book published by Packt
Copy and paste, print, and bookmark content
On demand and accessible via a web browser
Thanks for purchasing this Packt book. At Packt, quality is at the heart of our editorial process. To help us improve, please leave us an honest review.
If you'd like to join our team of regular reviewers, you can e-mail us at [email protected]. We award our regular reviewers with free eBooks and videos in exchange for their valuable feedback. Help us be relentless in improving our products!
Preface
What this book covers
What you need for this book
Who this book is for
Conventions
Reader feedback
Customer support
Downloading the example code
Errata
Piracy
Questions
Introduction to Reactive Programming
Asynchronous programming
Concurrency
Parallel programming
Streams
Features of Streams
The sequential elements
Source of a stream
Performing operations
Performing automatic operations
Reactive Streams
What do Reactive Streams address?
Asynchronicity
Back pressure
Reactive Programming
Reactive Manifesto
Responsiveness
Resilience
Elastic
Message-driven
Scalable
Benefits of Reactive Programming
Reactive Extensions
RxJava
Advantages of RxJava
Project Reactor
The features of Project Reactor
Akka Streams
Actor
Ratpack
Aim of Ratpack
Quasar
MongoDB
Slick
Vert.x
The components of Vert.x
Reactive Streams in Java 9
The Technology Compatibility Kit (TCK)
API components
Reactive in and across JVM
ThreadPoolExecutor
ScheduledThreadPoolExecutor
The Fork/Join framework
Summary
Programming Paradigm Shift
Programming paradigm
Imperative programming
Procedural programming
Avoiding bugs
Functional programming
Need for functional programming
Concurrency
Functional programming in JVM
Functional interface
Lambda expressions
Advantages of using lambda expressions
Functional interfaces provided by JDK 8
Method reference
Streams API
Characteristics of functional programming
Declarative programming
Characteristics of declarative programming
Advantages of declarative programming
Operator fusion
Macro fusion
Micro fusion
Summary
Reactive Streams
Discussing the Collection framework
Streams in action
Delving into the Flow API
The building blocks
Publisher
The SubmissionPublisher class
Subscriber
The Subscription interface
The behavior of the Publisher-Subscriber system
Processor
The behavior of the Publisher-Processor-Subscriber system
Designing nonblocking interfaces
Understanding backpressure
Summary
Reactive Types in RxJava
ReactiveX
Observer design pattern
The Iterator design pattern
Advantages of ReactiveX
RxJava
Observable Streams
Components of RxJava
Observable
Observer
Subscriber
Hot or cold Observables
Creating Observable emitting sequential data
Using the just() operator
Using the defer() operator
Using the empty() operator
Using the never() operator
Using the error() operator
Using the create() operator
Transforming Rx non-compatible sequences into Observables
Conversion using the from() operator
Creating Observables for unrestricted infinite length
The interval() operator
The range() operator
The timer() operator
Types of observables
The Observable<T> operator
Scenarios for using an Observable
The Single<T> operator
The Flowable<T> operator
Scenarios to use Flowable
The Maybe<T> operator
Completable
Understanding the Disposable interface
Disposable Subscribers
The DefaultSubscriber class
DisposableSubscriber
The ResourceSubscriber interface
CompositeDisposable
Subject
Flavors of Subject
The AsyncSubject class
The BehaviorSubject class
ReplaySubject
PublishSubject
Summary
Operators
Demystifying RxMarbles using an Observable
Transforming Observables using operators
Using the buffer() operator
Using the flatMap() operator
Using the groupBy() operator
Using the map() operator
Using the scan() operator
Using the window() operator
Filtering Observable
Using the debounce() operator
Using the distinct() operator
Using the distinctUntilChanged() operator
Using the elementAt() operator
Using the filter() operator
Using the first(), never(), and empty() operators
Using the last() operator
Using the ignoreElements() operator
Using the sample() operator
Using the skip() operator
Using the skipLast() operator
Using the take() operator
Using the takeLast() operator
Combining Observables
Using the merge() operator for combining observables
Using the combineLatest() operator
Using the startWith() operator
Using the and(), then(), and when() operators
Using the switchIfEmpty() operator
Using the zip() operator
Using the join() operator
Conditional operators
Using the all() operator
Using the amb() operator
Using the contains() operator
Using the defaultIfEmpty() operator
Using the sequenceEqual() operator
Using the takeWhile() operator
The mathematical and aggregate operators
Using the average() operator
Using the concat() operator
Using the count() operator
Using the max() operator
Using the min() operator
Using the reduce() operator
Using the sum() operator
Summary
Building Responsiveness
Concurrency
Comparing asynchronicity with concurrency
Scheduling
Scheduler
The subscribeOn() operator
The observeOn() operator
Schedulers
The computation() method
The from() operator
Th io() operator
The single() operator
The newThread() operator
The trampoline() operator
Operators and thread safety
Operators are not thread safe
The serialize() operator
Latency
Summary
Building Resiliency
Resilience
Reliable applications
Resiliency
Error handling in RxJava
Exploring the doOnError() operator
Reacting to an error
Recovering from an error
Absorb the error and switch over to the backup Observable which allows continuing the sequence using the onErrorResumeNext() operator
Absorb the error and emit a specified default item using the onErrorReturn() operator
Absorb the error and then try to restart the Observable that has failed using the onExceptionResumeNext() operator
Absorb the error and then try to restart the Observable which has failed using the retry() operator without delay
Absorb the error and then try to restart the Observable that has failed using the retryWhen() operator with delay
Exceptions specific to RxJava
CompositeException
MissingBackpressureException
OnErrorNotImplementedException
OnErrorFailedException
OnErrorThrowable
Error handler
Handling specific undeliverable exceptions
Exceptions introduced for tracking
Exception wrapping
Summary
Testing
Testing the need and role of a developer
The traditional way of testing an Observable
The modern approach for testing an Observable
The BaseTestConsumer class
The TestObserver class
The TestSubscriber class
Testing time-based Observable
The TestScheduler class
Testing the Subscriber
The test() operator
Testing notifications
Demonstration 1 - updating code for the just() operator
Demonstration 2 - updating the code for the never() operator
Demonstration 3 - updating the code for Flowable
Demonstration 4 - updating the code for the error() operator
Demonstration 5 - updating the code for the interval() operator
Mockito testing
Summary
Spring Reactive Web
An introduction to Spring Framework
Plumbing code
Scalability
Boilerplate code
Unit testing of the application
Features of the Spring Framework
POJO-based development
Loose coupling through Dependency Injection (DI)
Declarative programming
Boilerplate code reduction using aspects and templates
The Spring architecture
Core modules
Data access and integration modules
Web MVC and remoting modules
AOP modules
Instrumentation modules
Test modules
Project Reactor
Operators
Spring web Reactive Programming
Server-side support
Annotation-based support
The functional programming model
HandlerFunction
ServerRequest
ServerResponse
RouterFunction
Client side
Creating a WebClient instance
Using the WebClient instance to prepare a request
Reading the response
Deploying the application
Deploying the application from Eclipse IDE
Creating and deploying WAR file on server
Testing the application
Working with WebTestClient
Server-Sent Events (SSE)
Summary
Implementing Resiliency Patterns Using Hystrix
Hystrix- an introduction
How Hystrix works
Demonstrating HystrixCommand
Demonstrating HystrixObservableCommand
Handling fallback
Demonstrating HystrixCommand with a fallback
Demonstrating HystrixObservableCommand with fallback
Design patterns in resiliency
Bulkhead pattern
Partition the services
Partition the resources
Benefits
Circuit breaker
Proxy states
Closed state
Open state
Half-Open state
Retry pattern
Retry
Retrying after delay
Cancel
Queue-based load leveling pattern
Patterns used by Hystrix
Fail-fast
Fail-silent
Static fallback
Stubbed fallback
Cache via network fallback
Dual-mode fallback
Isolation
Using threads and thread pools for isolation
Reasons for using thread pools in Hystrix
Benefits of using thread and thread pools
Drawbacks of the thread pool
Semaphores
Request collapsing or request batching
The working
Request caching
Difference between request collapsing and request caching
Summary
Reactive Data Access
Spring Data
Modules provided by Spring Data
Features of Spring Data
Spring Data repositories
Using the repository
Spring Data and Reactive Programming
ReactiveCrudRepository
RxJava2CrudRepository
Spring Data Reactive and MongoDB
Features added to Spring Data MongoDB 2.0
Using MongoDB with Spring
RecativeMongoTemplate
Spring Data Repositories and MongoDB
ReactiveMongoRepository
Spring Data Reactive and Redis
Connecting to Redis
Jedis Connector
Lettuce connector
RedisTemplate
Spring Data Repositories and Redis
Kafka
Reactive API for Kafka
Reactor Kafka components for handling reactive pipelines
Sender
Creating the Sender
Creating messages
Sending messages
Closing the Sender
Receiver
Creating a Receiver instance
Reading the messages
Running the Kafka application
Summary
At the moment, technology plays a major role in the success of businesses and in reaching out to more users as early as possible. This demand will increase day by day. Along with the increase in the demand, the user expectations also have increased. Now, the users are demanding a quick, more responsive, and reliable response. Reactive programming is a programming model that helps in tackling the essential complexity that comes with writing such applications. We, as Java developers, are very much familiar with the imperative style of programming; however, now to tackle the essential complexity, reactive programming uses declarative and functional paradigms to build the programs. This book aims at making the paradigm shift easily by discussing the concepts about functional programming in depth.
This book begins with explaining what reactive programming and the Reactive Manifesto is, and about the Reactive Streams specification. It uses Java 9 to introduce the declarative and functional paradigm, which is very necessary to write programs in reactive style. It explains Java 9's Flow API, an adoption of the Reactive Streams specification. From this point on, it focuses on RxJava 2.0, covering topics like such as creating, transforming, filtering, combining, and testing Observables. It will then talk about how to use Java's popular framework, Spring, to build event-driven, reactive apps and its deployment on the server. By the end of the book, readers you will be fully equipped with the tools and techniques to implement robust event-driven reactive applications.
Chapter 1, Introduction to Reactive Programming, explores reactive programming by explaining different terms used in reactive systems such as responsiveness, resiliency, elasticity, scalable, and message driven and much more. We will discuss RxJava, Project Reactor, Akka, and Ratpack as reactive extensions available in the market.
Chapter 2, Programming Paradigm Shift, is designed in such a way that you will smoothly shift from imperative programming to declarative programming since we, as Java developers, are using imperative style of coding to write the code. However, reactive programming is concentrated around functional programming, which is new to most of us. The chapter is designed in such a way that you will smoothly shift from imperative programming to declarative programming. This chapter is full of demos which help you to understand how to use functional programming that enables adoption of declarative programming and how to use functions as value types. We will discuss lambda expression, functional interfaces, lazy evaluation, and functional composition in depth. We will also discover the operator fusion in this chapter.
Chapter 3, Reactive Streams, talks about Java 8 Streams and the newly introduced Flow API in Java 9. We will be discussing Publisher, Subscriber, Processor, and Subscription as backbones of Flow API. The ill application design may ruin the efforts of creating nonblocking applications. In this chapter, we will also discuss in depth about designing a nonblocking interface to achieve the goal.
Chapter 4, Reactive Types in RxJava, helps you in understanding RxJava as another implementation of Reactive Streams. You will explore in detail about the important types in RxJava that represent the producer and consumer of asynchronous events and the subscription, which gets created when a consumer subscribes to a consumer.
Chapter 5, Operators, focuses on the extensions of reactive extensions, known as operators in RxJava that enables asynchronous events to be filtered and transformed. We will discuss various ways of combining streams of events from different sources. You will explore the operators and their working using RxMarbles diagrams.
Chapter 6, Building Responsiveness, explores RxJava Scheduler and how RxJava uses Schedulers to execute asynchronous flow in different threads or at periodically or at scheduled times. We will discuss the differences between concurrency and parallelism and the criteria for selection of one versus the other.
Chapter 7, Building Resiliency, dives deep into resiliency. The chapter discusses various kinds of failures that can happen while building asynchronous flow. We will also discuss how RxJava approaches error handling and how to use the various error handling operators and utilities provided by RxJava.
Chapter 8, Testing, explores all about testing reactive applications. We will discuss the difference between testing traditional application and application designed for reactive applications. We will discuss various tips and tricks around unit testing the asynchronous flows. RxJava provides various testing utilities which that makes unit testing the flows easier.
Chapter 9, Spring Reactive Web, talks about the adoption of reactive programming by the Spring framework. The chapter gives an orientation of the Spring framework and of implementing reactive programming by developing an application.
Chapter 10, Implementing Resiliency Patterns Using Hystrix, discusses Hystrix, which is a latency and fault tolerance library from Netflix that uses RxJava. It shows how various resiliency patterns have been implemented within Hystrix.
Chapter 11, Reactive Data Access, talks about accessing the data from various data stores in a reactive fashion. You will explore reactive repositories using Spring Data Reactive, working with reactive Redis Access using Lettuce and reactive pipelines using Reactor Kafka.
The most important thing you need to go with reactive programming is practical knowledge of Java. Any person who has basic practical knowledge of JDK can start with reactive programming. The practical knowledge of JDK 8 will be an added advantage to go ahead. You will need the basic knowledge of JDK 9 as we are using it for development throughout the book. The basic knowledge of multithreading, JUnit, RESTFul web services, and Spring Framework 5.0 will be an added advantage. Practical knowledge of Eclipse IDE is required as we will be using it throughout the book.
The book is designed in such a way that it will be helpful for both beginners as well as the developers who are currently working with Java 8 or RxJava. The book will also be helpful for all those who want to start working with reactive programming using Java 9. In every chapter, we will start with a discussion of the very basic knowledge and then dive deep into the core concepts. The organization of the chapters will help the student of computer science who wants to upgrade their skills with the cutting edge concepts in the market. So, be active and give an attempt to reactive programming without fear.
In this book, you will find a number of text styles that distinguish between different kinds of information. Here are some examples of these styles and an explanation of their meaning. Code words in text, database table names, folder names, filenames, file extensions, pathnames, dummy URLs, user input and Twitter handles are shown as follows: "The buffer() operator accepts arguments of type integer where developers can specify how many items to bundle together."
A block of code is set as follows:
public class Demo_flatMap { public static void main(String[] args) { Observable.range(1,5).flatMap(item->Observable.range(item, 3)).subscribe(value->System.out.print(value+"->")); } }
Any command-line input or output is written as follows:
got:-12
got:-30
New terms and important words are shown in bold. Words that you see on the screen, for example, in menus or dialog boxes, appear in the text like this: "Many times, we click on the link to access very important information and suddenly we get a page saying No resource available or Service temporarily down."
Feedback from our readers is always welcome. Let us know what you think about this book-what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of. To send us general feedback, simply e-mail [email protected], and mention the book's title in the subject of your message. If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors.
Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.
You can download the example code files for this book from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you. You can download the code files by following these steps:
Log in or register to our website using your e-mail address and password.
Hover the mouse pointer on the
SUPPORT
tab at the top.
Click on
Code Downloads & Errata
.
Enter the name of the book in the
Search
box.
Select the book for which you're looking to download the code files.
Choose from the drop-down menu where you purchased this book from.
Click on
Code Download
.
Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:
WinRAR / 7-Zip for Windows
Zipeg / iZip / UnRarX for Mac
7-Zip / PeaZip for Linux
The code bundle for the book is also hosted on GitHub at https://github.com/PacktPublishing/Reactive-Programming-With-Java-9. We also have other code bundles from our rich catalog of books and videos available at https://github.com/PacktPublishing/. Check them out!
Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books-maybe a mistake in the text or the code-we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting http://www.packtpub.com/submit-errata, selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title. To view the previously submitted errata, go to https://www.packtpub.com/books/content/support and enter the name of the book in the search field. The required information will appear under the Errata section.
Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy. Please contact us at [email protected] with a link to the suspected pirated material. We appreciate your help in protecting our authors and our ability to bring you valuable content.
If you have a problem with any aspect of this book, you can contact us at [email protected], and we will do our best to address the problem.
The world is on the web. Nowadays, everyone uses the internet for banking applications, searching for information, online purchasing, marking products by companies, personal and professional communication via emails, and as a way to present themselves on public platforms, such as Twitter. We use the internet for personal as well as professional purposes. Most organizations have their websites, applications for mobiles, or some other way to exist on the internet. These organizations are wide-ranging. They have different functionalities and their nature of working is also very different. Also, they work in a variety of domains that need a lookalike of the developed application to serve all functionalities, application to serve more flexible, resilient, and robust functionalities. Application requirements, both from the user's perspective as well as the developer's perspective, have changed dramatically. The most important change now, which even a normal user may recognize, relates to the time taken for a response. You may be a technical person who understands terminologies such as a request, a response, or a server or someone who only knows how to browse and has no understanding of the technicalities of web programming. We all want answers on the web as quickly as possible. Today, no one wants to wait even for seconds to get the result or response they asked for; users demand a quick response. We are processing a huge amount of data as compared to applications developed in the past. Also, a lot of hardware-related changes have taken place. Today, instead of going with many servers for the deployment of an application, the preferred way is to deploy the application on the cloud. A cloud-based deployment makes the application more maintainable by saving hours of maintenance. Now, the market demands responsive, loosely coupled, scalable, resilient, and message-driven systems. The traditional approach to programming can't fulfil this requirement. The approach needs to be changed. We need to adapt to asynchronous, non-blocking reactive programming!
In this chapter, we will concentrate on the following points so as to get familiar with the terms, situations, and challenges in reactive programming:
Reactive Manifesto
Reactive Streams
Reactive Extensions
Reactive in a JVM
Reactive across JVMs
In the 90s, when Java actually started acquiring a grip on the market, many companies started developing applications using it. The basic reason was, it allowed you to do this with the applications--write once, run anywhere. The internet was still not so famous and had very few users. But, in the early 2000s, the conditions started changing dramatically. Billions of users were now using the internet for different reasons, and experts were aware of the increase in these numbers. So applications, specifically web applications, had to handle enormous traffic. From the development perspective, this led to problems of scalability and how to handle the pressure of so many requests. The users of a system also became more demanding with regard to look and feel along the way. They also demanded a quick response.
Consider a pharmaceutical application dealing in pharmaceutical products. The application helps find distributor information in an area, the price of the product, the details of the product, the stock, and other relevant things. Let's consider one of the functionalities of the application to get the list of distributors. When a user wants to find a list of the pharmaceutical distributors in his/her city or area, what will they do? Yes! They will either enter or select the name of the city to find the distributor list. After entering the data, the user just needs to click on a button to initiate the request.
We have two options as developers:
Keep the user waiting until the result has not been processed to find the list of the distributors that will be fetched from the database
Second, allow the user to proceed further and use other stuff in the application, such as finding product details, availability of products, and so on
Instead of discussing what a developer will do, you will ask, "If you are the user, which of the preceding scenarios would you have preferred?" Obviously, I will also choose not to wait. Instead, I'd enjoy the amazing functionality of the application which will eventually process the result. If you haven't recognized it yet, let me tell you that you have chosen parallel programming. Correct! You have preferred an asynchronous approach rather than the traditional synchronous approach. What is an asynchronous approach? If you are already aware of this, you can skip the discussion and go on to the next discussion.
The term asynchronous programming means parallel programming where some unit of work or functionality runs separately from the main application without blocking it. It's a model that allows you to take leverage of the multiple cores of the system. Parallel programming uses multiple CPU cores to execute the tasks, ultimately increasing the performance of the application. We know very well that each application has at least one thread, which we usually call the main thread. Other functionalities run in separate threads. We may call them child threads; they keep notifying the main thread about its progress as well as failure.
The major benefit provided by the asynchronous approach is that the performance and responsiveness of the application improve drastically. In today's world, the application market is too demanding. No one wants to be kept waiting while the application is processing things that one needs an answer for. No matter whether it's a desktop application or the web, users prefer to continue enjoying the application while the application is computing a complicated result or performing some expensive task on a resource. We need this in all the scenarios where developers don't want to block the user while using the application.
Now, you may be thinking of many questions: Do we need asynchronous programming? Should one choose asynchronous programming over concurrency? If yes, when do we need it? What are the ways? What are its benefits? Are there any flaws? What are the complications? Hold on! We will discuss them before we move ahead. So let's start with one interesting and well-known style of programming.
The term concurrency comes in whenever developers talk about performing more than one task at the same time. Though we keep on saying we do have tasks running simultaneously, actually they are not. Concurrency takes advantage of CPU time slicing, where the operating system chooses a task and runs a part of it. Then, it goes to the next task keeping the first task in the state of waiting.
The problems encountered in using a thread-based model are as follows:
Concurrency may block the processing, keeping the user waiting for the result, and also waste computational resources.
Some threads increase the performance of the applications and some degrade it.
It's an overhead to start and terminate many threads at the same time.
Sharing the available limited resource in multiple threads hampers performance.
If data is being shared between multiple threads, then it's complicated to maintain its state. Sometimes, it is maintained by synchronization or using locks, which complicates the situation.
Now, you may have understood that concurrency is a good feature, but it's not a way to achieve parallelism. Parallelism is a feature that runs a part of the task or multiple tasks on multiple cores at the same time. It cannot be achieved on a single core CPU.
Basically, the CPU executes instructions, usually one after another. Parallel programming is a style of programming in which the execution of the process is divided into small parts at the same time, with better use of multi-core processors. These small parts, which are generally called tasks, are independent of each other. Even the order of these tasks doesn't matter. A single CPU has performance limitations as well as the availability of memory, making parallel programming helpful in solving larger problems faster by utilizing the memory efficiently.
In any application, we have two things to complete as a developer. We need to design the functionalities that will help in continuing the flow of the application, helping users smoothly use their applications. Every application uses data to compute user requests. Thread-based models only help in the functional flow of the application. To process the data needed by the application, we need something more. But what do we need? We need a data flow computation that will help deal with data flows and their changes. We need to find the ease with which either static or dynamic data flows and the underlying model could use it. Also, changes in the data will be propagated through the data flow. It is reactive programming that will fulfil this requirement.
We are all very familiar with and frequently use the Collections framework to handle data. Though this framework enables a user to handle data quite efficiently, the main complexity lies in using loops and performing repeated checks. It also doesn't facilitate the use of multi-core systems efficiently. The introduction of Streams has helped to overcome these problems. Java 8 introduces Streams as a new abstract layer that enables the processing of data in a declarative manner.
A Stream is a series of different elements that have been emitted over a time period. Are Streams the same as an array? In a way, yes! They are like an array, but not an array. They do have distinct differences. The elements of an array are sequentially arranged in memory, while the elements in a Stream are not! Every Stream has a beginning as well as an end.
Let's make it simpler by discussing a mathematical problem. Consider calculating the average of the first six elements of an array and then Streams. Let's take the array first. What will we, as developers, do to calculate the average of an array? Yes, we will fetch each element from an array and then calculate their addition. Once we get the addition, we will apply the formula to calculate the average. Now, let's consider Streams. Should we apply the same logic as we just applied for an array? Actually, no! We should not directly start developing the logic. Before the logic, we must understand a very important thing that every single element in the Streams may not be visited. Also, each element from the Streams may be emitted at the same speed. So while the calculation is done, some elements may not have been visited at all. The calculated average is not the final value, but the answer will be of the values in motion. Confused?
Have you ever sat on the banks of a river or flowing water and put your legs in it? Most of us have at least once enjoyed this peaceful experience. The water moves around our legs and moves ahead. Have you ever observed the same flowing water passing through your legs twice? Obviously, not! It's the same when it comes to Streams.
We just discussed Streams; now let's discuss the features offered by Streams.
A Stream provides a sequence of the typical type of elements on demand.
As a Stream contains elements, it needs elements. A Stream can take Collections, Arrays, files, or any other I/O resource as its input.
Streams strongly support performing various operations, such as filtering, mapping, matching, finding, and many more, on their elements.
Streams don't need explicit iterations to perform on the elements from the source; they do the iteration implicitly.
Streams help in handling data. Today's application demands are oriented more toward live or real-time data operations. Today's world doesn't want only a collection of data; instead, most of the time, this is followed by modification and filtration. This processing requires more time, leading to performance bottlenecks. Streams help in turning this huge amount of data processed and provide a quick response. It means the ever-changing data in motion needs to be handled. The initiative of reactive streams started in late 2013 by engineers from Pivotal, Netflix, and Typesafe. Reactive Streams is a specification that has been developed for library developers. Library developers write code against Reactive Streams APIs. On the other hand, business developers work with the implementation of the Reactive Streams specification.
Business developers have to concentrate on the core business logic required for the application. Reactive Streams provide a level of abstraction to concentrate on the business logic instead of getting involved in low-level plumbing to handle streams.
We have just discussed Reactive Streams. The following are the features around which they are woven.
Today's application users don't like to wait for a response from the server. They don't care about the processing of the request--collecting the required information and then generating the response. They are just interested in getting a quick response without a block.
Asynchronous systems decouple the components of a system allowing the user to explore and use other parts of the application instead of wasting the time of the user in waiting for the response. Asynchrony enables parallel programming so as to compute the resources, collaborate the resources over the network, and collaborate with and use multiple cores of a CPU on a single machine to enhance the performance. In the traditional approach, developers compute one function after another. The time taken by the complete operation is the sum of the time taken by each of the functionalities. In the asynchronous approach, operations are carried out parallely. The total time taken to complete the operation here is the time taken by the longest operation and not the sum of each operation of the application. This ultimately enhances the performance of the application to generate a quicker response.
The Reactive Streams specification defines a model for back pressure. The elements in the Streams are produced by the producer at one end, and the elements are consumed by the consumer at the other end. The most favorable condition is where the rate at which the elements are produced and consumed is the same. But, in certain situations, the elements are emitted at a higher rate than they are consumed by the consumer. This scenario leads to the growing backlog of unconsumed elements. The more the backlog grows, the faster the application fails. Is it possible to stop the failure? And if yes, how to stop this failure? We can certainly stop the application from failing. One of the ways to do this is to communicate with the source or the publisher to reduce the speed with which elements are emitted. If the speed is reduced, it ultimately reduces the load on the consumer and allows the system to overcome the situation.
Back pressure plays a very vital role as a mechanism that facilitates a gradual response to the increasing load instead of collapsing it down. It may be a possibility that the time taken to respond may increase, leading to degradation; however, it ensures resilience and allows the system to redistribute the increasing load without failure.
The elements get published by the publisher and collected by the subscriber or consumer at the downstream. Now, the consumer sends a signal for the demand in the upstream, assuring the safety of pushing the demanded number of elements to the consumer. The signal is sent asynchronously to the publisher, so the subscriber is free to send more requests for more elements with a pull strategy.
The term reactive or Reactive Programming (RP) has been in use at least since the paper, The Reactive Engine was published by Alan Kay in 1969. But the thought behind Reactive Programming is the result of the effort taken by Conal Elliot and Paul Hudak who published a paper Function Reactive Animation in 1997. Later on, the Function reactive animation was developed, which is also referred to as functional reactive programming (FRP). FRP is all about the behavior and how the behavior is changing and interacting on the events. We will discuss FRP more in the next chapter. Now, let's only try to understand Reactive Programming.
RP designs code in such a way that the problem is divided into many small steps, where each step or task can be executed asynchronously without blocking each other. Once each task is done, it's composed together to produce a complete flow without getting bound in the input or output.
RP ensures it matches the requirements of the everyday changing market and provides a basis for developing scalable, loosely coupled, flexible, and interactive applications. A reactive application focuses on the systems that react to the events, the varying loads, and multiple users. It also reacts effectively to all the conditions, whether it's successful or has failed to process the request. The Reactive system supports parallel programming to avoid blocking of the resources in order to utilize the hardware to its fullest. This is totally opposite to the traditional way of programming. Reactive Programming won't keep the resources busy and allows them to be used by other components of the system. Reactive systems ensure they provide features such as responsiveness, resilience, elasticity, scalability, and a message-driven approach. Let's discuss these features one by one.
Responsiveness is the most important feature of an application and ensures quick and effective responses with consistent behavior. This consistent behavior ensures the application will handle errors as well.
Applications that delay in giving a response are regarded by the users as not functioning well, and soon they start ignoring them. Responsiveness is a major feature required in today's applications. It optimizes resource utilization and prepares the system for the next request. When we open a web page that has too many images, it usually takes more time to open the images, but the content of the page gets displayed before the images. What just happened? Instead of keeping the user waiting for the web page, we allowed him/her to use the information and refer to the images once downloaded. Such applications are called more responsive applications.
For resilience, the application will be responsive even in the event of a failure, making it resilient. Let's consider a situation. We have requested for data from the server. While the request is getting processed, the power supply fails. Obviously, all the resources and the data coming from the server as a response will suddenly become unavailable. We need to wait until the power supply is restarted and the server starts taking the load again. What if the server has an alternative power supply in case the main supply fails. Yes, no one has to wait as the alternative supply keeps the server running and enables it to work without fail. All of this happens only because the alternative supply replaces the main power supply. It's a kind of clustering. In the same way, the application may be divided into components that are isolated from each other so that even if one part of the system fails, it will recover without any kind of compromise, providing a complete application experience.
Reactive programs react to the changes that happen in the input by allocating resources as per the requirements so as to achieve high performance. The reactive system achieves this elasticity by providing a scaling algorithm. The elastic system has the provision to allocate more resources to fulfil the increasing demand. Whenever the load increases, the application can be scaled up by allocating more resources, and if the demand decreases, it removes them so as to not waste the resources.
Let's consider a very simple example. One day, a few of your friends visit your house without prior intimation. You will be surprised and will welcome them happily. Being a good host, you will offer them coffee or cold drinks and some snacks. How will you serve drinks? Normally, we'd use some of the coffee mugs or glasses that we always keep to one side so that we can use them if required. After the use, will you keep them again with your daily crockery? No! We will again keep them aside. This is what we call elasticity. We have the resources, but we will not use them unless required.
Reactive systems use an asynchronous message, passing between the components for communication, to achieve isolation and loose coupling without blocking the resources. It facilitates easy to extend, maintainable applications that are flexible as well.
The market is changing day by day, so are the client demands too. The workload on an application cannot be fully predictable. The developers need an application that will be able to handle increasing pressure, but in case it doesn't, then they need an application that is easily scalable. Scalability is not only in terms of code, but it must be able to adopt new hardware as well. This is the same as that of elasticity. No, it's not. Don't get confused between these two terminologies.
We'll consider the same example we discussed to understand elasticity, but with a change. Your friends inform you that they are coming this weekend. Now, you are well aware and want to be prepared for the party. Suddenly you realize you don't have enough glasses to serve the soft drinks. What will you do? Very simple, you will buy some use-and-throw glasses. What did you do? You scaled up your hardware by adding more resources.
The benefits of RP are as follows:
It increases the performance of the application
It increases the utilization of computing resources on a multi-core
It provides a more maintainable approach to deal with asynchronous programming
It includes back pressure, which plays a vital role to avoid over-utilization of the resources
Reactive Extensions are the set of the tools that allow operations on sequential data without considering whether the data is synchronous or asynchronous. They also provide a set of sequence operators that can be operated on each of the items in sequence. There are many libraries that implement the Reactive Streams specification. The libraries that support Reactive Programming include Akka, Reactor, RxJava, Streams, Ratpack, and Vert.x.
ReactiveX has been implemented as a library for languages such as JavaScript, Ruby, C#, Scala, C++, Java, and many more. RxJava is the Reactive Extension for JVM, specifically for Java. It is open source. It was created by Netflix in 2014 and published under the Apache 2.0 license. It has been created to simplify concurrency on the server side. The main goal of RxJava is to enable the client to invoke a heavy request that will be executed in parallel on the server.
Now we are well aware that in Reactive Programming, the consumer reacts to the incoming data. Reactive programming basically propagates the changes in the events to the registered observers. The following are the building blocks of the RxJava :
Observable
: The observable represents the source of the data. The observable emits the elements which vary in numbers. There is no fixed number of elements to be emitted, it could vary. The observable could successfully emit the elements or with an error if something goes wrong. At a time the observable can have any number of the subscribers.
Observer or Subscriber
: The subscribers listen to the observables. It consumes the elements emitted by the observable.
Methods
: The set of methods enables the developers to handle, modify and compose the data.
Following are the methods used in RxJava programming:
onNext()
: When a new item is emitted from the observable, the
onNext()
method is called on each subscriber
onComplete()
: When the observable finishes the data flow successfully, the
onComplete()
method gets called
onError()
: The
onError()
method will be called in situations where the observable finishes data emission with an error
The following are a few of the advantages of RxJava:
It allows a chain of asynchronous operations
To keep track of the state, we usually need to maintain a counter variable or some variable to maintain the previously calculated value; however, in RxJava, we don't need to get involved in keeping track of the state
It has a predefined way to handle errors that occur between the processes
Spring 5 supports Reactive Programming to make more responsive and better-performing applications. Spring was added with Spring web reactive and reactive HTTP as new components along with support for Servlet 3.1 specification. Pivotal or Spring developed the Reactor as a framework for asynchronous programming. It enables writing of high-performance applications and works asynchronously using the event-driven programming paradigm. The Reactor uses the design pattern, where the services are received from the clients, and distributes them to different event handlers, where their processing will be done.
The Reactor is a Reactive Programming foundation, specifically for JVMs. It supports unblocking fully. The Project Reactor aims to address a very important drawback of the traditional approach by supporting asynchronicity. It provides an efficient way to handle back pressure. It also focuses on the following aspects, making it more useful for Reactive Programming:
It facilitates the use of the rich operators to manipulate a data flow
Data keeps flowing until someone doesn't subscribe to it
