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.kts
plugins {
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。