AsyncLoadingCache本文档将向您展示如何在 Vert.x 应用程序中使用 Caffeine 的 AsyncLoadingCache。
您将构建一个在网页中轮播图像的应用程序。
图像将由服务器从公共 API 下载,该 API 暴露在 https://http.cat。
每张图片都以 🐱 的形式代表一个 HTTP 状态码。
准备好了吗?
| 注意 | 图片由 Tomomi Imura 创建 (@girlie_mac) | 
文本编辑器或 IDE,
Java 11 或更高版本,
Maven 或 Gradle。
此项目的代码包含功能等效的 Maven 和 Gradle 构建文件。
以下是您应该使用的 pom.xml 文件的内容
pom.xml<?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>async-loading-cache-caffeine-howto</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <vertx.version>5.0.0.CR2</vertx.version>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </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-core</artifactId>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web</artifactId>
    </dependency>
    <dependency>
      <groupId>io.vertx</groupId>
      <artifactId>vertx-web-client</artifactId>
    </dependency>
    <dependency>
      <groupId>com.github.ben-manes.caffeine</groupId>
      <artifactId>caffeine</artifactId>
      <version>3.1.5</version>
    </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.caffeine.CatsVerticle</mainClass>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>假设您使用带有 Kotlin DSL 的 Gradle,您的 build.gradle.kts 文件应如下所示
build.gradle.ktsplugins {
  java
  application
}
repositories {
  mavenCentral()
}
java {
  toolchain {
    languageVersion.set(JavaLanguageVersion.of(11))
  }
}
dependencies {
  implementation(platform("io.vertx:vertx-stack-depchain:5.0.0.CR2"))
  implementation("io.vertx:vertx-core")
  implementation("io.vertx:vertx-web")
  implementation("io.vertx:vertx-web-client")
  implementation("com.github.ben-manes.caffeine:caffeine:3.1.5")
}
application {
  mainClass = "io.vertx.howtos.caffeine.CatsVerticle"
}index.html 网页主要由以下部分组成
body 中的一个 <img> 标签,以及
一个脚本,在页面加载后更改图像的 src 属性。
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Rotating Cats Page</title>
  <script type="application/javascript">
    window.onload = function () { // (2)
      const codes = [ // (3)
        100,
        200, 201, 204, 206,
        301, 302, 303, 304, 307, 308,
        401, 403, 404, 406, 407, 409, 410, 412, 416, 418, 425, 451,
        500, 501, 502, 503, 504,
      ]
      setInterval(function () { // (4)
        let img = document.getElementById("cat-img"); // (5)
        img.src = "/api/cats/" + codes[Math.floor(Math.random() * codes.length)]; // (6)
      }, 250)
    }
  </script>
</head>
<body>
<div>
  <img src="/api/cats/200" id="cat-img" alt="Cat image"/> <!--(1)-->
</div>
</body>
</html>body 中 id 设置为 cat-img 的 img 标签
页面加载时运行脚本函数
定义一些 HTTP 状态码
以 250 毫秒的固定延迟周期性地调度函数执行
使用其 id 从 DOM 中检索 img 元素
使用随机选择的 HTTP 状态码更新 src 属性
我们将需要一个 Vert.x Web 客户端实例来获取图像
    request = WebClient.create(vertx)
      .request(GET, new RequestOptions().setHost("http.cat").setPort(443).setSsl(true))
      .as(BodyCodec.buffer());我们还需要一个缓存,因为我们不想使后端 API 过载
    cache = Caffeine.newBuilder() // (1)
      .expireAfterWrite(Duration.ofMinutes(1)) // (2)
      .recordStats() // (3)
      .executor(cmd -> context.runOnContext(v -> cmd.run())) // (4)
      .buildAsync((key, exec) -> CompletableFuture.supplyAsync(() -> { // (5)
        Future<Buffer> future = fetchCatImage(key); // (6)
        return future.toCompletionStage(); // (7)
      }, exec).thenComposeAsync(Function.identity(), exec));
    vertx.setPeriodic(20000, l -> { // (8)
      CacheStats stats = cache.synchronous().stats();
      log.info("Stats: " + stats);
    });创建一个缓存构建器
配置缓存项在 1 分钟后过期
启用统计记录
定义一个在 verticle 上下文上调用任务的执行器
使用缓存执行器创建一个异步加载器,该加载器必须返回一个 CompletableFuture
获取猫咪图片
将 Vert.x Future 转换为 CompletionStage
定期记录缓存统计信息
| 注意 | 执行器定义和复杂的加载器实现在此处并非严格必要。 事实上,我们将部署一个 verticle 实例,将缓存绑定到字段,并始终从事件循环中调用其方法。如果这是您的用例,您可以将设置简化为 然而,如果您计划部署 verticle 的多个实例并在它们之间共享缓存,请坚持使用之前的实现。它保证异步加载器始终在正确的上下文中调用。 | 
获取猫咪图片包括使用相应的 HTTP 状态码作为 URI 将请求发送到后端
  private Future<Buffer> fetchCatImage(int code) {
    return request.uri("/" + code)
      .send()
      .expecting(HttpResponseExpectation.SC_OK)
      .map(HttpResponse::body);
  }使用 Vert.x Web,为我们的 API 和静态文件创建 HTTP 服务器非常简单
    Router router = Router.router(vertx);
    router.get("/api/cats/:id").produces("image/*").handler(this::handleImageRequest);
    router.get().handler(StaticHandler.create());
    return vertx.createHttpServer()
      .requestHandler(router)
      .listen(8080)
      .onSuccess(v -> log.info("Server started on port 8080"));以下是我们如何实现图像请求处理
  private void handleImageRequest(RoutingContext rc) {
    Integer code = Integer.valueOf(rc.pathParam("id")); // (1)
    CompletableFuture<Buffer> completableFuture = cache.get(code); // (2)
    Future<Buffer> future = Future.fromCompletionStage(completableFuture, context); // (3)
    future.onComplete(ar -> { // (4)
      if (ar.succeeded()) {
        rc.response()
          .putHeader("Cache-Control", "no-store") // (5)
          .end(ar.result());
      } else {
        rc.fail(ar.cause());
      }
    });
  }从请求路径中检索指定的代码
调用 Caffeine(如果需要,图像将从后端透明地加载)
将 Caffeine 返回的 CompletableFuture 转换为 Vert.x Future
完成后,将图像字节(或失败)发送到客户端
指示浏览器禁用图像缓存(否则,对于给定的代码,它只会查询我们的服务器一次!)
CatsVerticle 需要一个 main 方法
  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx(); // (1)
    vertx.deployVerticle(new CatsVerticle()).await(); // (2)
  }创建一个 Vert.x 实例
部署 CatsVerticle
您可以从以下位置运行应用程序
您的 IDE,通过运行 CatsVerticle 类中的 main 方法,或者
使用 Maven:mvn compile exec:java,或者
使用 Gradle:./gradlew run (Linux, macOS) 或 gradlew run (Windows)。
浏览到 https://:8080。
您应该会在网页中看到猫咪图片轮播
 
一段时间后,检查程序输出。您应该会看到类似以下内容:
Mar 22, 2022 3:45:17 PM io.vertx.howtos.caffeine.CatsVerticle lambda$start$4
INFO: Stats: CacheStats{hitCount=52, missCount=28, loadSuccessCount=28, loadFailureCount=0, totalLoadTime=2514949257, evictionCount=0, evictionWeight=0}
Mar 22, 2022 3:45:37 PM io.vertx.howtos.caffeine.CatsVerticle lambda$start$4
INFO: Stats: CacheStats{hitCount=132, missCount=28, loadSuccessCount=28, loadFailureCount=0, totalLoadTime=2514949257, evictionCount=0, evictionWeight=0}
Mar 22, 2022 3:45:57 PM io.vertx.howtos.caffeine.CatsVerticle lambda$start$4
INFO: Stats: CacheStats{hitCount=212, missCount=28, loadSuccessCount=28, loadFailureCount=0, totalLoadTime=2514949257, evictionCount=0, evictionWeight=0}
Mar 22, 2022 3:46:17 PM io.vertx.howtos.caffeine.CatsVerticle lambda$start$4
INFO: Stats: CacheStats{hitCount=267, missCount=53, loadSuccessCount=52, loadFailureCount=0, totalLoadTime=3337599348, evictionCount=28, evictionWeight=28}
Mar 22, 2022 3:46:37 PM io.vertx.howtos.caffeine.CatsVerticle lambda$start$4
INFO: Stats: CacheStats{hitCount=344, missCount=56, loadSuccessCount=56, loadFailureCount=0, totalLoadTime=3480880213, evictionCount=28, evictionWeight=28}
请注意 hitCount、missCount 或 evictionCount 中的变化。
本文档涵盖了
用于发出 HTTP 请求的 Vert.x web 客户端,
Vert.x web 服务器和路由器,
Caffeine 异步加载缓存与 Vert.x 应用程序的集成,
Vert.x 周期性任务。
最后发布:2025-02-01 01:26:03 +0000。