<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>io.vertx.howtos</groupId>
<artifactId>service-proxy-howto</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<vertx.version>5.0.0.CR2</vertx.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-stack-depchain</artifactId>
<version>${vertx.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-codegen</artifactId>
<classifier>processor</classifier>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-service-proxy</artifactId>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web-client</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.5.0</version>
<configuration>
<mainClass>io.vertx.howtos.ebservice.BeersApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
Create a Vert.x Event Bus Service with Service Proxy
This document will show you how to bootstrap an Event Bus service using Vert.x Service Proxy module. As you will see, this approach is particularly useful when you want to design and consume a service on the event bus using plain Java interfaces.
What you will build
You will build a Vert.x application that exposes and uses BarmanService
, an Event Bus Service that generates beers and manages customer bills. We are going to deploy two verticles: the BarmanVerticle
that exposes the service and the DrunkVerticle
that consumes the service
What you need
-
A text editor or IDE
-
Java 11 higher
-
Maven
Create a project
Here is the content of the pom.xml
file you should be using:
pom.xml
You must import both vertx-codegen
with processor
classifier and vertx-service-proxy
. We are going to use vertx-web-client
to load the beer names.
Design the BarmanService
First, we must define our service interface. Under the hood, a code generator analyze it and generates the event bus message handler and the proxy class.
This is the BarmanService
interface:
package io.vertx.howtos.ebservice.beers;
import io.vertx.codegen.annotations.ProxyGen;
import io.vertx.codegen.annotations.VertxGen;
import io.vertx.core.Future;
import io.vertx.core.Vertx;
@VertxGen
@ProxyGen (1)
public interface BarmanService {
Future<Beer> giveMeARandomBeer(String customerName); (2)
Future<Integer> getMyBill(String customerName); (3)
void payMyBill(String customerName); (4)
static BarmanService createProxy(Vertx vertx, String address) { (5)
return new BarmanServiceVertxEBProxy(vertx, address);
}
}
1 | Add @VertxGen and @ProxyGen to trigger code generation |
2 | Define the method that generates a new beer and adds it to the bill of the customer specified. When the beer is ready, the Future is completed. |
3 | Define the method that retrieves the bill. |
4 | Define the method that settles the bill. This is a fire and forget method. |
5 | Specify the method that creates a new proxy. BarmanServiceVertxEBProxy is the class name of the proxy that the code generator will create for us. |
There are a couple of rules you must follow when defining the service interface. Look at Restrictions for service interface for more info. In our interface, we are using a couple of primitives and Beer
, a POJO annotated as @DataObject
. If you want to use types annotated with DataObject
inside your interface, they must define both a constructor with only a JsonObject
parameter and a toJson()
method that returns a JsonObject
.
To trigger the code generation, you must also add in the same package of the interface a package-info.java
with @ModuleGen
annotation:
@ModuleGen(groupPackage = "io.vertx.howtos.ebservice", name = "beers")
package io.vertx.howtos.ebservice.beers;
import io.vertx.codegen.annotations.ModuleGen;
Implement the BarmanService
Now you can implement the BarmanService
.
For giveMeARandomBeer()
:
@Override
public Future<Beer> giveMeARandomBeer(String customerName) {
return webClient
.get(443, "www.craftbeernamegenerator.com", "/api/api.php?type=classic") (1)
.ssl(true)
.send()
.expecting(HttpResponseExpectation.SC_OK) (2)
.map(bufferHttpResponse -> {
JsonObject result = bufferHttpResponse.bodyAsJsonObject();
Beer beer = new Beer( (3)
result.getJsonObject("data").getString("name"),
result.getJsonObject("data").getString("style"),
3 + random.nextInt(5)
);
System.out.println("Generated a new Beer! " + beer);
bills.merge(customerName, beer.getPrice(), Integer::sum); (4)
return beer;
});
}
1 | Send a request to the Craft Beer Name Generator Service |
2 | Fail the async method if the request to external service failed |
3 | Create a new Beer |
4 | Add the beer to the customer bill |
For getMyBill()
:
@Override
public Future<Integer> getMyBill(String customerName) {
return Future.succeededFuture(bills.get(customerName));
}
For settleMyBill()
:
@Override
public void payMyBill(String customerName) {
bills.remove(customerName);
System.out.println("Removed debt of " + customerName);
}
Expose the service
Now we can expose the service inside the BarmanVerticle
with the ServiceBinder
class:
package io.vertx.howtos.ebservice;
import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.client.WebClient;
import io.vertx.howtos.ebservice.beers.BarmanService;
import io.vertx.howtos.ebservice.beers.impl.BarmanServiceImpl;
import io.vertx.serviceproxy.ServiceBinder;
public class BarmanVerticle extends VerticleBase {
@Override
public Future<?> start() {
BarmanService service = new BarmanServiceImpl(WebClient.create(vertx)); (1)
MessageConsumer<JsonObject> consumer = new ServiceBinder(vertx) (2)
.setAddress("beers.services.myapplication") (3)
.register(BarmanService.class, service);(4)
return consumer.completion();
}
}
1 | Instantiate the BarmanServiceImpl |
2 | Instantiate the ServiceBinder |
3 | Configure the service address |
4 | Register the service on the event bus |
Use the service
Now we can use the service with the generated proxy. For demo purposes, we’re going to use it inside another verticle called DrunkVerticle
:
package io.vertx.howtos.ebservice;
import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.howtos.ebservice.beers.BarmanService;
public class DrunkVerticle extends VerticleBase {
@Override
public Future<?> start() {
BarmanService barmanService = BarmanService.createProxy(vertx, "beers.services.myapplication"); (1)
return barmanService.giveMeARandomBeer("homer") (2)
.onSuccess(beer1 -> System.out.println("My first beer is a " + beer1.getName() + " and it costs " + beer1.getPrice() + "€")) (3)
.compose(v -> vertx.timer(1500))
.compose(v -> barmanService.giveMeARandomBeer("homer")) (4)
.onSuccess(beer2 -> System.out.println("My second beer is a " + beer2.getName() + " and it costs " + beer2.getPrice() + "€")) (5)
.compose(v -> barmanService.getMyBill("homer")) (6)
.onSuccess(bill -> {
System.out.println("My bill with the bar is " + bill + "€");
barmanService.payMyBill("homer"); (7)
});
}
}
1 | Instantiate the proxy |
2 | Let’s try the first beer 🍺 |
3 | Drinking the first one 🍻 |
4 | Give me another one 🍺 |
5 | Drinking the second one 🍻 |
6 | Time to go home. Give me the bill |
7 | Pay the bill |
Running the application
To run the application deploy the BarmanVerticle
and subsequently the DrunkVerticle
.
package io.vertx.howtos.ebservice;
import io.vertx.core.Vertx;
public class BeersApplication {
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new BarmanVerticle()).await();
System.out.println("The barman is ready to serve you");
vertx.deployVerticle(new DrunkVerticle()).await();
vertx.close().await();
}
}
You can run the application from:
-
your IDE, by running the
main
method from theBeersApplication
class, or -
with Maven:
mvn compile exec:java
You should see something like this:
The barman is ready to serve you Generated a new Beer! Manticore's Shorthand Barleywine (Barleywine) My first beer is a Manticore's Shorthand Barleywine and it costs 6€ Generated a new Beer! Fortunate Pretzel (Cream Ale) My second beer is a Fortunate Pretzel and it costs 6€ My bill with the bar is 12€ Removed debt of homer
Summary
This how-to explained to you:
-
How to design and implement an Event Bus Service using Vert.x Service Proxy, and
-
How to expose the service on the event bus, and
-
How to use the service