<?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>
使用服务代理创建 Vert.x 事件总线服务
本文档将向您展示如何使用 Vert.x 服务代理模块来启动一个事件总线服务。您会发现,当您希望使用纯 Java 接口在事件总线上设计和消费服务时,这种方法特别有用。
您将构建什么
您将构建一个 Vert.x 应用程序,它暴露并使用 BarmanService
,这是一个事件总线服务,用于生成啤酒和管理客户账单。我们将部署两个 verticle:暴露服务的 BarmanVerticle
和消费服务的 DrunkVerticle
您需要什么
-
文本编辑器或 IDE
-
Java 11 或更高版本
-
Maven
创建项目
以下是您应该使用的 pom.xml
文件的内容
pom.xml
您必须同时导入带有 processor
分类器的 vertx-codegen
和 vertx-service-proxy
。我们将使用 vertx-web-client
来加载啤酒名称。
设计 BarmanService
首先,我们必须定义我们的服务接口。在底层,代码生成器会分析它并生成事件总线消息处理器和代理类。
这是 BarmanService
接口
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 | 添加 @VertxGen 和 @ProxyGen 以触发代码生成 |
2 | 定义生成新啤酒并将其添加到指定客户账单的方法。当啤酒准备好后,Future 将完成。 |
3 | 定义检索账单的方法。 |
4 | 定义结账的方法。这是一个即发即弃的方法。 |
5 | 指定创建新代理的方法。BarmanServiceVertxEBProxy 是代码生成器将为我们创建的代理的类名。 |
定义服务接口时必须遵循一些规则。有关更多信息,请参阅服务接口的限制。在我们的接口中,我们使用了一些基本类型和 Beer
,一个被 @DataObject
注解的 POJO。如果您想在接口内部使用被 DataObject
注解的类型,它们必须定义一个仅带 JsonObject
参数的构造函数和一个返回 JsonObject
的 toJson()
方法。
要触发代码生成,您还必须在与接口相同的包中添加一个带有 @ModuleGen
注解的 package-info.java
@ModuleGen(groupPackage = "io.vertx.howtos.ebservice", name = "beers")
package io.vertx.howtos.ebservice.beers;
import io.vertx.codegen.annotations.ModuleGen;
实现 BarmanService
现在您可以实现 BarmanService
。
对于 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 | 向精酿啤酒名称生成器服务发送请求 |
2 | 如果对外部服务的请求失败,则使异步方法失败 |
3 | 创建新的 Beer |
4 | 将啤酒添加到客户账单 |
对于 getMyBill()
@Override
public Future<Integer> getMyBill(String customerName) {
return Future.succeededFuture(bills.get(customerName));
}
对于 settleMyBill()
@Override
public void payMyBill(String customerName) {
bills.remove(customerName);
System.out.println("Removed debt of " + customerName);
}
暴露服务
现在我们可以使用 ServiceBinder
类在 BarmanVerticle
中暴露服务
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 | 实例化 BarmanServiceImpl |
2 | 实例化 ServiceBinder |
3 | 配置服务地址 |
4 | 在事件总线上注册服务 |
使用服务
现在我们可以使用生成的代理来使用服务。出于演示目的,我们将在另一个名为 DrunkVerticle
的 verticle 中使用它
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 | 实例化代理 |
2 | 我们来尝尝第一杯啤酒 🍺 |
3 | 喝第一杯 🍻 |
4 | 再来一杯 🍺 |
5 | 喝第二杯 🍻 |
6 | 该回家了。给我账单 |
7 | 支付账单 |
运行应用程序
要运行应用程序,请部署 BarmanVerticle
,然后部署 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();
}
}
您可以从以下方式运行应用程序
-
在您的 IDE 中,通过运行
BeersApplication
类中的main
方法,或者 -
使用 Maven:
mvn compile exec:java
您应该会看到类似这样的内容
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
总结
本操作指南向您解释了
-
如何使用 Vert.x 服务代理设计和实现事件总线服务,以及
-
如何在事件总线上暴露服务,以及
-
如何使用服务