tags | projects | ||
---|---|---|---|
|
This guide walks you through the process of creating an asynchronous, event-driven system using the Reactor project.
You’ll build an application that fires off events to fetch a random Spring Boot quote, and then asynchronously gathers them together.
For this event-driven example, you’ll fetch quotes from The Spring Boot quote database. The JSON format looks like this:
{
"type": "success",
"value": {
"id": 10,
"quote": "Really loving Spring Boot, makes stand alone Spring apps easy."
}
}
The easiest thing to do is capture the inner value
, i.e. the quote, with one class and then wrap the whole in another class.
src/main/java/hello/Quote.java
link:complete/src/main/java/hello/Quote.java[role=include]
This class contains both the id
and the quote
text supplied from the website. @JsonIgnoreProperties(ignoreUnknown=true)
signals that any other attributes are to be ignored.
The wrapper class looks like this:
src/main/java/hello/QuoteResource.java
link:complete/src/main/java/hello/QuoteResource.java[role=include]
The wrapper class has the type
attribute along with a Quote
. This makes it easy later to use Spring’s RestTemplate
and convert JSON to a POJO with the Jackson binding library.
An asynchronous application has publishers and receivers. To create the receiver, implement a receiver with a method to respond to events:
src/main/java/hello/Receiver.java
link:complete/src/main/java/hello/Receiver.java[role=include]
The Receiver
implements the Consumer
interface by implementing the accept()
method. It is geared to receive Event<Integer>
.
For this example, every time the Receiver
receives an integer, it fetches another Spring Boot quote using Spring’s RestTemplate
. Then it signals its completion to the CountDownLatch
to coordinate when all events have been processed.
Receiver
has the @Service
annotation so it will be automatically registered with the application context.
The next step is to publish a handful of events to the reactor.
src/main/java/hello/Publisher.java
link:complete/src/main/java/hello/Publisher.java[role=include]
The code uses a for loop to publish a fixed number of events. An AtomicInteger
is used to fashion a unique number, which gets turned into a Reactor event with Event.wrap()
. The event is published to the quotes channel using reactor.notify()
.
Note
|
Reactor events can contain any type of POJO. This guide uses a very simple integer, but a more detailed event can be used if more information needs to be transmitted to the receiver. |
Receiver
has the @Service
annotation so it will be automatically registered with the application context.
Note
|
The code is a bit contrived in that it manually sends a fixed number of integers. In production, this would be replaced by some triggering input, perhaps using Reactor’s TcpServer to respond to incoming data.
|
The final step in putting together your application is to register the components and then invoke them.
src/main/java/hello/Application.java
link:complete/src/main/java/hello/Application.java[role=include]
The Reactor environment is defined with the environment()
method. The environment gets fed into the reactor()
method to create an asynchronous reactor. In this case, you are using the THREAD_POOL
dispatcher.
Note
|
Reactor has four dispatchers to pick from: synchronous, ring buffer, thread pool, and event loop.
|
It also defines the number of events to send at the top with NUMBER_OF_QUOTES
and creates a CountDownLatch
with the latch()
method.
The Application
class is tagged with the @Configuration
and @ComponentScan
annotations. This lets it define the application context while also scanning the hello
package for the @Service
objects.
The main()
method fetches the reactor
and the receiver
. It then registers the receiver
to digest events on the "quotes" selector. With everything registered, it uses the Publisher
to send out a series of quote-fetching events.
The CountDownLatch
then waits until every thread reports that it’s done before proceeding.
You should see output similar to this:
Quote 5: The real benefit of Boot, however, is that it's just Spring. That means any direction the code takes, regardless of complexity, I know it's a safe bet. Quote 8: The real benefit of Boot, however, is that it's just Spring. That means any direction the code takes, regardless of complexity, I know it's a safe bet. Quote 7: Working with Spring Boot is like pair-programming with the Spring developers. Quote 1: Really loving Spring Boot, makes stand alone Spring apps easy. Quote 3: @springboot with @springframework is pure productivity! Who said in #java one has to write double the code than in other langs? #newFavLib Quote 2: Really loving Spring Boot, makes stand alone Spring apps easy. Quote 4: Really loving Spring Boot, makes stand alone Spring apps easy. Quote 6: Previous to Spring Boot, I remember XML hell, confusing set up, and many hours of frustration. Quote 10: Spring has come quite a ways in addressing developer enjoyment and ease of use since the last time I built an application using it. Quote 9: Really loving Spring Boot, makes stand alone Spring apps easy. Elapsed time: 206ms Average time per quote: 20ms
The events were dispatched in order, one through ten. But the output shows that they were consumed asynchronously due to the results being out of order.
Congratulations! You’ve just developed an asynchronous, message-driven system using the Reactor project. This is just the beginning of what you can build with it.