使用服务代理创建 Vert.x 事件总线服务

本文档将向您展示如何使用 Vert.x 服务代理模块引导事件总线服务。如您所见,当您想使用纯 Java 接口在事件总线上设计和消费服务时,这种方法特别有用。

您将构建什么

您将构建一个 Vert.x 应用程序,它公开并使用 BarmanService,这是一个生成啤酒和管理客户账单的事件总线服务。我们将部署两个 Verticle:公开服务的 BarmanVerticle 和消费服务的 DrunkVerticle

您需要什么

  • 文本编辑器或 IDE

  • Java 11 或更高版本

  • Maven

创建项目

以下是您应该使用的 pom.xml 文件的内容

您必须导入带有 processor 分类器的 vertx-codegenvertx-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 参数的构造函数和一个返回 JsonObjecttoJson() 方法。

要触发代码生成,您还必须在接口的同一个包中添加一个带有 @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();
  }
}

您可以从以下位置运行应用程序

  1. 您的 IDE,通过运行 BeersApplication 类的 main 方法,或

  2. 使用 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

总结

本操作指南向您解释了

  1. 如何使用 Vert.x 服务代理设计和实现事件总线服务,以及

  2. 如何在事件总线上公开服务,以及

  3. 如何使用服务


最后发布:2025-02-08 00:41:15 +0000。