1. 概述
本文将深入探讨 Vert.x 框架,解析其核心概念,并手把手教你构建一个简单的 RESTful Web 服务。我们将从基础概念切入,逐步过渡到 HTTP 服务器搭建,最终完成完整的 RESTful 服务实现。
2. Vert.x 是什么
Vert.x 是 Eclipse 开源的一款反应式、多语言支持的开发工具包。它专为构建高性能、可伸缩的应用而设计。
反应式编程是一种基于异步流的编程范式,专注于对变化和事件的响应。Vert.x 通过事件总线实现组件间通信,当事件发生时异步传递给处理器。
我们称其为多语言工具包,因为它同时支持 JVM 和非 JVM 语言,包括:
- ✅ Java
- ✅ Groovy
- ✅ Ruby
- ✅ Python
- ✅ JavaScript
3. 环境搭建
使用 Vert.x 需要添加 Maven 依赖:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-core</artifactId>
<version>3.9.15</version>
</dependency>
最新版本可在 Maven 中央仓库 查询。
4. Verticle 组件
Verticle 是 Vert.x 引擎执行的基本代码单元。工具包提供了多个抽象 verticle 类,可按需扩展实现。
得益于多语言特性,Verticle 可用任何支持的语言编写。典型应用由多个在同一 Vert.x 实例中运行的 Verticle 组成,通过事件总线进行事件通信。
在 Java 中创建 Verticle,需实现 io.vertx.core.Verticle
接口或其子类:
public class HelloVerticle extends AbstractVerticle {
@Override
public void start(Future<Void> future) {
LOGGER.info("Welcome to Vertx");
}
}
5. 事件总线
事件总线是 Vert.x 应用的神经系统。作为反应式框架,Verticle 在接收到消息或事件前保持休眠状态。组件间通过事件总线通信,消息可以是字符串或复杂对象。
消息处理本质是异步的:
- 消息进入事件总线队列
- 发送方立即获得控制权
- 消息出队传递给监听 Verticle
- 响应通过
Future
和回调机制返回
6. 简单 Vert.x 应用
我们来创建一个包含 Verticle 的简单应用,并通过 vertx
实例部署它。创建 Verticle 需继承 io.vertx.core.AbstractVerticle
类并重写 start()
方法:
public class HelloVerticle extends AbstractVerticle {
@Override
public void start(Future<Void> future) {
LOGGER.info("Welcome to Vertx");
}
}
start()
方法在 Verticle 部署时由 vertx
实例调用。参数 io.vertx.core.Future
用于检测异步部署状态。
部署 Verticle 的代码:
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new HelloVerticle());
}
同样可重写 stop()
方法(关闭时调用):
@Override
public void stop() {
LOGGER.info("Shutting down application");
}
7. HTTP 服务器
现在用 Verticle 创建 HTTP 服务器:
@Override
public void start(Future<Void> future) {
vertx.createHttpServer()
.requestHandler(r -> r.response().end("Welcome to Vert.x Intro"))
.listen(config().getInteger("http.port", 9090),
result -> {
if (result.succeeded()) {
future.complete();
} else {
future.fail(result.cause());
}
});
}
关键点解析:
- 重写
start()
创建服务器并附加请求处理器 requestHandler()
在每次收到请求时触发- 服务器绑定端口后,通过
listen()
的回调判断启动状态 config.getInteger()
从外部conf.json
读取端口配置
测试服务器代码:
@Test
public void whenReceivedResponse_thenSuccess(TestContext testContext) {
Async async = testContext.async();
vertx.createHttpClient()
.getNow(port, "localhost", "/", response -> {
response.handler(responseBody -> {
testContext.assertTrue(responseBody.toString().contains("Hello"));
async.complete();
});
});
}
测试依赖(vertx-unit + JUnit):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-unit</artifactId>
<version>3.9.15</version>
<scope>test</scope>
</dependency>
测试类中的 Verticle 部署:
@Before
public void setup(TestContext testContext) {
vertx = Vertx.vertx();
vertx.deployVerticle(SimpleServerVerticle.class.getName(),
testContext.asyncAssertSuccess());
}
关闭 Vert.x 实例:
@After
public void tearDown(TestContext testContext) {
vertx.close(testContext.asyncAssertSuccess());
}
⚠️ 测试要点:@Before
方法接收 TestContext
参数,用于控制异步行为。deployVerticle()
的第二个参数 testContext.asyncAssertSuccess()
会等待 Verticle 中的 future.complete()
或 future.fail()
调用,失败时自动终止测试。
8. RESTful Web 服务
基于 HTTP 服务器构建 RESTful 服务,需要额外引入 vertx-web 模块:
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-web</artifactId>
<version>3.9.15</version>
</dependency>
8.1. 路由器与路由
创建路由器并定义 GET 路由:
Router router = Router.router(vertx);
router.get("/api/baeldung/articles/article/:id")
.handler(this::getArticles);
处理器方法实现:
private void getArticles(RoutingContext routingContext) {
String articleId = routingContext.request()
.getParam("id");
Article article = new Article(articleId,
"This is an intro to vertx", "baeldung", "01-02-2017", 1578);
routingContext.response()
.putHeader("content-type", "application/json")
.setStatusCode(200)
.end(Json.encodePrettily(article));
}
执行流程:
- 路由器匹配请求路径
- 调用关联的处理器方法
- 从
RoutingContext
提取路径参数id
- 构建 Article 对象
- 设置响应头、状态码并返回 JSON
8.2. 集成路由器到服务器
将路由器添加到 HTTP 服务器:
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(config().getInteger("http.port", 8080),
result -> {
if (result.succeeded()) {
future.complete();
} else {
future.fail(result.cause());
}
});
关键改动:requestHandler(router::accept)
指示服务器在收到请求时调用路由器的 accept()
方法。
测试 REST 服务:
@Test
public void givenId_whenReceivedArticle_thenSuccess(TestContext testContext) {
Async async = testContext.async();
vertx.createHttpClient()
.getNow(8080, "localhost", "/api/baeldung/articles/article/12345",
response -> {
response.handler(responseBody -> {
testContext.assertTrue(
responseBody.toString().contains("\"id\" : \"12345\""));
async.complete();
});
});
}
9. 应用打包
使用 Maven Shade 插件打包为可执行 JAR:
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>io.vertx.core.Starter</Main-Class>
<Main-Verticle>com.baeldung.SimpleServerVerticle</Main-Verticle>
</manifestEntries>
</transformer>
</transformers>
<artifactSet />
<outputFile>
${project.build.directory}/${project.artifactId}-${project.version}-app.jar
</outputFile>
</configuration>
配置说明:
Main-Verticle
:应用入口 VerticleMain-Class
:Vert.x 启动器类,负责创建vertx
实例并部署主 Verticle
10. 总结
本文系统介绍了 Vert.x 工具包及其核心概念,通过实战演示了:
- HTTP 服务器搭建
- RESTful Web 服务开发
- 使用 vertx-unit 进行测试
- 打包为可执行 JAR
Vert.x 的反应式模型和事件驱动架构,使其成为构建高性能服务的利器。掌握这些基础后,可以进一步探索其分布式特性、集群支持等高级功能。