Vert.x Verticles
Jakob Jenkov |
The term verticle is the name of the components you can deploy to Vert.x. A verticle is in some ways similar to a Servlet or a message driven EJB in Java EE. However, verticles work differently, and the concurrency model under which verticles and Servlets and EJBs execute is different. This text will take a closer look at how to create and deploy verticles in Vert.x, and how verticles can communicate with each other over the internal event bus.
Implementing a Verticle
You implement a verticle by creating a class that extends io.vertx.core.AbstractVerticle
.
Here is an example verticle class:
import io.vertx.core.AbstractVerticle; public class BasicVerticle extends AbstractVerticle { }
The class BasicVerticle
extends AbstractVerticle
but it doesn't have any functionality.
We will add that in the following sections.
start()
The AbstractVerticle
class contains a start()
method which you can override in your
verticle class. The start()
method is called by Vert.x when the verticle is deployed and ready to
start. Here is how implementing the start()
method looks:
public class BasicVerticle extends AbstractVerticle { @Override public void start() throws Exception { System.out.println("BasicVerticle started"); } }
The start()
method is where you initialize your verticle.
Inside the start()
method you will normally create e.g. HTTP or TCP server, register event handlers
on the event bus, deploy other verticles, or whatever else your verticle needs to do its work.
The AbstracVerticle
class also contains another version of start()
which takes a
Future
as parameter. This Future
can be used to asynchronously tell Vert.x if the Verticle
was deployed successfully.
You will see later in this tutorial how to use both versions of the start()
method.
stop()
The AbstractVerticle
class also contains a stop()
method you can override. The
stop()
method is called when Vert.x shuts down and your verticle needs to stop. Here is an example of
overriding the stop()
method in your own verticle:
public class BasicVerticle extends AbstractVerticle { @Override public void start() throws Exception { System.out.println("BasicVerticle started"); } @Override public void stop() throws Exception { System.out.println("BasicVerticle stopped"); } }
Deploying a Verticle
Once you have created a Verticle you need to deploy it inside Vert.x in order to execute it. Here is how you deploy a verticle:
public class VertxVerticleMain { public static void main(String[] args) throws InterruptedException { Vertx vertx = Vertx.vertx(); vertx.deployVerticle(new BasicVerticle()); } }
First a Vertx
instance is created. Second, the deployVerticle()
method is called
on the Vertx
instance, with an instance of your verticle (BasicVerticle
in this example)
as parameter.
Vert.x will now deploy the verticle internally. Once Vert.x deploys the verticle,
the verticle's start()
method is called.
The verticle will be deployed asynchronously, so the verticle may not be deployed by the time the
deployVerticle()
method returns. If you need to know exactly when a verticle is fully deployed,
you can provide a Handler
implementation to the the deployVerticle()
. Here is how that
looks:
vertx.deployVerticle(new BasicVerticle(), new Handler<AsyncResult<String>>() { @Override public void handle(AsyncResult<String> stringAsyncResult) { System.out.println("BasicVerticle deployment complete"); } });
Or using a Java lambda expression :
vertx.deployVerticle(new BasicVerticle(), stringAsyncResult -> { System.out.println("BasicVerticle deployment complete"); });
Deploying a Verticle From Another Verticle
It is possible to deploy one verticle from inside another verticle. Here is an example:
public class BasicVerticle extends AbstractVerticle { @Override public void start() throws Exception { System.out.println("BasicVerticle started"); vertx.deployVerticle(new SecondVerticle()); } @Override public void stop() throws Exception { System.out.println("BasicVerticle stopped"); } }
Using The Event Bus
It is very common for verticles to either listen for incoming messages from the event bus, or to write messages to other verticles via the event bus. Therefore I will show you how to do both in the following sections.
Listening for Messages
When a verticle wants to listen for messages from the event bus, it listens on a certain address. An address is just a name (a String) which you can choose freely.
Multiple verticles can listen for messages on the same address. This means that an address is not unique to a single verticle. An address is thus more like the name of a channel you can communicate via. Multiple verticles can listen for messages on an address, and multiple verticles can send messages to an address.
A verticle can obtain a reference to the event bus via the vertx
instance inherited from
AbstractVerticle
Here is how listening for messages on a given address looks:
public class EventBusReceiverVerticle extends AbstractVerticle { public void start(Future<Void> startFuture) { vertx.eventBus().consumer("anAddress", message -> { System.out.println("1 received message.body() = " + message.body()); }); } }
This example shows a verticle that registers a consumer (listener) of messages on the Vert.x event bus.
The consumer is registered with the address anAddress
, meaning it consumes messages sent to this
address via the event bus.
The consumer is a handler object which contains a single method. That is why it is implemented above using a lambda expression.
Sending Messages
Sending messages via the event bus can be done via either the send()
or publish()
method
on the event bus.
The publish
method sends the message to all verticles listening on a given address.
The send()
method sends the message to just one of the listening verticles. Which verticle receives
the message is decided by Vert.x. At the time of writing the Vert.x docs says that a verticle is chosen using a
"non-strict round robin" algorithm. This basically means that Vert.x will try to distribute the messages evenly
among the listening verticles. This is useful for distributing work load over multiple verticles (e.g. threads or CPUs).
Here is an example that deploys two event bus consumers (listeners), and one event bus sender. The sender sends two messages
to a given address. The first message is sent via the publish()
method, so both consumers receive the
message. The second message is sent via the send()
method, so only one of the consumers will receive the
message.
Vertx vertx = Vertx.vertx(); vertx.deployVerticle(new EventBusReceiverVerticle("R1")); vertx.deployVerticle(new EventBusReceiverVerticle("R2")); Thread.sleep(3000); vertx.deployVerticle(new EventBusSenderVerticle());
public class EventBusSenderVerticle extends AbstractVerticle { public void start(Future<Void> startFuture) { vertx.eventBus().publish("anAddress", "message 2"); vertx.eventBus().send ("anAddress", "message 1"); } }
public class EventBusReceiverVerticle extends AbstractVerticle { private String name = null; public EventBusReceiverVerticle(String name) { this.name = name; } public void start(Future<Void> startFuture) { vertx.eventBus().consumer("anAddress", message -> { System.out.println(this.name + " received message: " + message.body()); }); } }
If you run this code you will see that the first message is received by both consumers (R1 + R2) whereas the second message is only received by one of the consumers.
Tweet | |
Jakob Jenkov |