HTTP 与 Web 开发

使用 Infinispan 客户端存储 Web Session

本指南将向你展示如何使用 Vert.x Web Infinispan 扩展将用户会话(Sessions)持久化存储在分布式内存网格 Infinispan 中。

你将构建什么

你将构建一个 Vert.x Web 应用程序,页面将展示:

  • 会话 ID 以及该会话的创建时间戳;

  • 当前页面的实时动态生成时间。

run

整个应用程序仅包含一个简洁的 ServerVerticle 类。

前置要求

  • 文本编辑器或 IDE

  • Java 11 或更高版本

  • Maven 或 Gradle

  • 本地运行的 Infinispan 集群(或 Docker)

创建工程项目

本项目同时提供 Maven 与 Gradle 两种等价构建配置。

使用 Maven

以下是该项目所使用的 pom.xml 构建配置文件内容:

使用 Gradle

使用 Gradle Kotlin DSL 时对应的 build.gradle.kts 文件:

使用 Infinispan 存储与检索 Session 数据

Vert.x Web 的 SessionStore 接口为读写管理用户会话提供了统一标准抽象。

InfinispanSessionStore 实现类位于 io.vertx:vertx-web-sstore-infinispan 依赖组件中。

以下是 ServerVerticle 类的核心代码:

package io.vertx.howtos.web.sessions;

import io.vertx.core.Future;
import io.vertx.core.VerticleBase;
import io.vertx.core.Vertx;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.Session;
import io.vertx.ext.web.handler.SessionHandler;
import io.vertx.ext.web.sstore.SessionStore;
import io.vertx.ext.web.sstore.infinispan.InfinispanSessionStore;

import java.util.Date;

public class ServerVerticle extends VerticleBase {

  public static final String TEMPLATE = ""
    + "Session [%s] created on %s%n"
    + "%n"
    + "Page generated on %s%n";

  @Override
  public Future<?> start() {
    Router router = Router.router(vertx);

    JsonObject options = new JsonObject()
      .put("servers", new JsonArray()
        .add(new JsonObject()
          .put("host", "localhost")
          .put("port", 11222)
          .put("username", "admin")
          .put("password", "bar"))
      );
    SessionStore store = InfinispanSessionStore.create(vertx, options); (1)

    router.route().handler(SessionHandler.create(store)); (2)

    router.get("/").handler(ctx -> {
      Session session = ctx.session();
      session.computeIfAbsent("createdOn", s -> System.currentTimeMillis()); (3)

      String sessionId = session.id();
      Date createdOn = new Date(session.<Long>get("createdOn"));
      Date now = new Date();

      ctx.end(String.format(TEMPLATE, sessionId, createdOn, now)); (4)
    });

    return vertx.createHttpServer()
      .requestHandler(router)
      .listen(8080);
  }

  public static void main(String[] args) {
    Vertx vertx = Vertx.vertx();
    vertx.deployVerticle(new ServerVerticle()).await();
  }
}
1 使用目标 Infinispan 集群连接参数(主机名、端口与访问凭据)创建 InfinispanSessionStore 实例;
2 注册全局 SessionHandler,负责自动化拦截并管理 Vert.x Web 用户会话;
3 在当前会话属性中存入会话创建时间戳;
4 拼装响应 HTML 并写回浏览器客户端。

运行与测试应用

如果你对 Infinispan 尚不熟悉,建议先行浏览其 官方入门介绍。

你可以使用 Docker 在本地一秒拉起单机版 Infinispan 服务节点:

docker run -p 11222:11222 -e USER="admin" -e PASS="bar" infinispan/server:14.0
若你本地已有独立运行的 Infinispan 实例,请记得同步核对并修改 ServerVerticle 中的网络端口与账密配置。

启动 Vert.x Web 应用:

  1. 在 IDE 中直接右键运行 ServerVerticle;

  2. 使用 Maven:mvn compile exec:java;

  3. 使用 Gradle:./gradlew run。

验证高可用会话漂移与容灾

  1. 在浏览器中访问 http://localhost:8080。当你首次发起请求时,会话创建时间应当与页面生成时间完全一致。

  2. 现在,模拟 Web 服务端宕机迁移场景:在终端按下 Ctrl+C 强行停止 Vert.x 应用,然后重新启动它。

  3. 服务重启后,刷新浏览器页面。你会发现会话 ID 与初次创建时间保持完全不变,仅页面生成时间发生了更新。这充分证明了会话数据已经安全持久化在独立的 Infinispan 分布式网格中,成功实现 Web 节点的无状态化与高可用自愈。

本文总结

本指南向你阐明了:

  1. 创建并配置 InfinispanSessionStore 存储实例;

  2. 注册 Vert.x Web SessionHandler 处理管道;

  3. 在分布式会话中存取业务状态数据。