Not so long ago a new version of the most popular Java framework was released:
Spring Framework 5 . The new version has brought a lot of new. One of the biggest innovations is the reactive programming model. Spring Boot 2 will be released very soon, which will significantly simplify the creation of microservices with this approach.
If you, like me, want to find out in more detail what it is and how it is used, then welcome under cat. The article is divided into two parts - theoretical and practical. Now we will try to figure out what it means to be reactive. After that, we will try to use this knowledge to write our own microservice (
part 2 ).
What is reactivity?
To begin, consider the concept of reactivity. And here it is necessary to make a clear distinction in the definitions immediately.
Reactive system
A reactive system is an architectural pattern that satisfies a certain set of rules (
reactive manifesto ). This monifest was developed in 2013 to eliminate uncertainty. The fact is that at that time in Europe and the United States the term “reactive” was too excessive. Everyone understood in his own way what system could be called reactive. This gave rise to enormous confusion, and eventually a manifesto was created that establishes clear criteria for the reactive system.
')
Let's look at the picture from the manifest and analyze in more detail what each item means:

- Responsive . This principle tells us that the system being developed must respond quickly and for a predetermined predetermined time. In addition, the system must be sufficiently flexible for self-diagnosis and repair.
What does this mean in practice? Traditionally, when requesting a service, we go to the database, extract the required amount of information and give it to the user. Everything is good here, if our system is fast enough and the database is not very large. But what if the response time is much longer than expected? In addition, the user could have lost the Internet for several milliseconds. Then all efforts to sample the data and form the answer disappear. Remember gmail or facebook. When you have a bad Internet, you do not get an error, but simply wait for the result more than usual. In addition, this clause tells us that the answers and requests should be streamlined and consistent. - Resilient . The system remains operational even if one of the components has failed. In other words, the components of our system must be sufficiently flexible and isolated from each other. This is achieved by replication. If, for example, one PostgreSQL replica fails, you need to ensure that the other is always available. In addition, our application should work in multiple instances.
- Elastic . This principle suggests that the system should occupy the optimal amount of resources in each period of time. If we have a high load, then we need to increase the number of application instances. In the case of a low load, the resources of free machines should be cleared. Typical tools for implementing this principle: Kubernetes .
- Message driven . This is where the most important point for a Java developer begins. This is the issue that our application should attend to. Communication between services should occur through asynchronous messages. This means that each element of the system requests information from another element, but does not expect to receive the result immediately. Instead, he continues to perform his tasks. This allows you to increase the use of system resources and manage more flexible errors. Typically, this result is achieved through reactive programming.
Reactive programming
According to Wikipedia, reactive programming is a programming paradigm focused on data streams. Very soon we will look at how this works in practice. But first, let's see what this paradigm is based on.
The basic concept of reactive programming is based on non-blocking input / output. Usually when accessing a certain resource (database, file on disk, remote server, etc.) we get the result immediately (often in the same line). In case of non-blocking access to a resource, our thread does not stop accessing and continues execution. The result we get later and if necessary.
Practice
Fine! Now we will start implementation of reactive programming in
Java . The only thing to note is that we will use
Spring WebFlux . This is a new framework for reactive programming. The question arises, why did the
Spring team not use
Spring Web MVC for this purpose? The fact is that not all modules in this framework can be used for working in reactive mode. There are a lot of code and third-party libraries, for example,
Tomcat , which are based on declarative programming and threads.
In the process of working on the framework, a small
specification was developed for asynchronous work. Later this specification was decided to be included in Java 9. However, I will use Java 8 and Spring Boot 2 for simplicity.
Basic concepts
In the new approach, we have two main classes for working in jet mode:
- Mono
The Mono class is needed for working with a single object. Let's see how a simple application will look like using Mono . To do this, create a project and the User entity in it (all settings and examples can be found on my profile in github ):
@Data @NoArgsConstructor @AllArgsConstructor public class User { private String firstName; private String lastName; }
Next, create a class with tests and prepared users:
public class HabrreactiveApplicationTests { private User peter = new User("Peter", "Griffin"); private User lois = new User("Lois", "Griffin"); private User brain = new User("Brain", "Griffin"); }
Let's write a test:
@Test public void mono() {
As you can see from the example, using the reactive approach is quite simple.
In addition, the Mono class has many methods for every occasion. For example, there is a well-known map method for converting one type to another:
@Test public void blockMono() { Mono<User> monoPeter = Mono.just(peter);
- Flux
This class is similar to Mono , but provides the ability to work asynchronously with many objects:
@Test public void flux() {
As in the case of Mono , Flux has a set of useful methods:
@Test public void fluxFilter() { Flux<User> userFlux = Flux.just(peter, lois, brain);
It should emphasize one feature. Unlike the standard (non-daemon) threads, when the main thread completes its work, the collection of our data stops and the program ends. This can be easily demonstrated. The following code will not output anything to the console:
@Test public void fluxDelayElements() { Flux<User> userFlux = Flux.just(peter, lois, brain);
This can be avoided using the CountDownLatch class:
@Test public void fluxDelayElementsCountDownLatch() throws Exception {
All this is very simple and efficient in terms of resources. Imagine what can be gained by combining calls to stream methods.
In this article, we examined the concept of the
reactive system and
reactive programming . In addition, we understand how these concepts are connected. In the next part we will go further and try to build our service based on the knowledge gained.
PS I propose to disassemble
the messaging system from mail.ru. Do you think this application can be called
a message system according to the manifest? Write your thoughts in the comments. Very interesting.