1. 简介
本文将介绍 Quarkus 框架中的 quarkus-websockets-next 扩展。这是一个新的实验性扩展,用于在应用中支持 WebSocket 协议。
⚠️ Quarkus WebSockets Next 是替代旧版 Quarkus WebSockets 扩展的解决方案,使用更简单且性能更优。
与 Quarkus 的一贯风格不同,该扩展不支持 Jakarta WebSockets API,而是提供了一套简化且更现代化的 WebSocket 操作方式。它通过自定义注解和方法实现功能,不仅增强了灵活性,还内置了 JSON 支持等特性。
尽管如此,Quarkus WebSockets Next 仍基于 Quarkus 核心构建,这意味着我们既能获得预期的性能和可扩展性,又能享受 Quarkus 带来的开发体验。
2. 依赖配置
新建项目
如果创建全新项目,可直接使用 Maven 命令生成已包含 websockets-next
扩展的项目结构:
$ mvn io.quarkus.platform:quarkus-maven-plugin:3.16.4:create \
-DprojectGroupId=com.example.demo \
-DprojectArtifactId=quarkus-websockets-demo \
-Dextensions='websockets-next'
⚠️ 必须使用
io.quarkus.platform:quarkus-maven-plugin
,因为该扩展仍处于实验阶段。
现有项目集成
对于已有项目,只需在 pom.xml
添加依赖:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-websockets-next</artifactId>
</dependency>
3. 服务端接口
安装扩展后,即可开始使用 WebSocket。服务端接口通过 @WebSocket
注解创建:
@WebSocket(path = "/echo")
public class EchoWebsocket {
// WebSocket 实现代码
}
这会创建一个监听指定路径的接口。和 Quarkus 其他特性一样,路径支持参数和固定路径。
3.1 消息回调
要让接口发挥作用,需要处理消息。WebSocket 支持文本和二进制两种消息类型,通过 @OnTextMessage
和 @OnBinaryMessage
注解处理:
@OnTextMessage
public String onMessage(String message) {
return message;
}
这个简单示例实现了回声服务器:将收到的消息原样返回。
若需处理二进制消息,使用 @OnBinaryMessage
注解:
@OnBinaryMessage
public Buffer onMessage(Buffer message) {
return message;
}
此时接收和返回的是 io.vertx.core.buffer.Buffer
对象,包含原始消息字节。
3.2 方法参数与返回值
消息处理方法不仅能接收原始消息,Quarkus 还能注入多种参数:
规则: 消息处理方法必须且只能有一个表示消息载荷的参数,其类型决定访问方式:
Buffer
或byte[]
:原始字节String
:解码后的字符串JsonObject
/JsonArray
:JSON 解码- 其他类型:自动反序列化为 JSON
@OnTextMessage
public Message onTextMessage(Message message) {
return message;
}
record Message(String message) {}
✅ 返回值规则:
- 支持上述所有类型
- 返回
void
表示不发送响应
其他可用参数
路径参数(通过
@PathParam
):@WebSocket(path = "/chat/:user") public class ChatWebsocket { @OnTextMessage(broadcast = true) public String onTextMessage(String message, @PathParam("user") String user) { return user + ": " + message; } }
连接对象(
WebSocketConnection
):@OnTextMessage public Map<String, String> onTextMessage(String message, WebSocketConnection connection) { return Map.of( "message", message, "connection", connection.toString() ); }
通过连接对象可获取:
- 唯一连接 ID
- 连接建立时间
- URL 路径参数
- 手动发送消息或关闭连接
@OnTextMessage
public void onTextMessage(String message, WebSocketConnection connection) {
if ("close".equals(message)) {
connection.sendTextAndAwait("Goodbye");
connection.closeAndAwait();
}
}
3.3 连接生命周期回调
除了消息处理,还能监听连接打开(@OnOpen
)和关闭(@OnClose
)事件:
@OnOpen
public void onOpen() {
LOG.info("连接已建立");
}
@OnClose
public void onClose() {
LOG.info("连接已关闭");
}
这些回调不能接收消息载荷,但支持其他参数类型。
@OnOpen
方法可返回值,连接建立后立即发送给客户端:
@OnOpen
public String onOpen(WebSocketConnection connection) {
return "欢迎, " + connection.id();
}
3.4 访问连接对象
方式一:CDI 注入
将 WebSocketConnection
作为 CDI Bean 注入(仅限 WebSocket 上下文):
@ApplicationScoped
public class CdiConnectionService {
@Inject
WebSocketConnection connection;
}
❌ 在非 WebSocket 上下文(如 HTTP 请求)中调用会抛出
ContextNotActiveException
方式二:所有连接管理
注入 OpenConnections
管理所有活跃连接:
@Inject
OpenConnections connections;
可用于查询或广播消息:
public void sendToAll(String message) {
connections.forEach(conn -> conn.sendTextAndAwait(message));
}
✅ 此方式可在任何上下文中使用
3.5 错误处理
通过 @OnError
注解处理回调中的异常:
@OnError
public String onError(RuntimeException e) {
return e.toString();
}
规则:
- 必须包含异常参数
- 支持多异常处理(按精确度匹配)
@OnError
public String onIoException(IOException e) {
// 处理 IOException 及其子类
}
@OnError
public String onException(Exception e) {
// 处理其他 Exception(排除 IOException)
}
4. 客户端 API
Quarkus 同样支持编写 WebSocket 客户端。
4.1 基础连接器
使用 BasicWebSocketConnector
实现原始消息收发:
@Inject
BasicWebSocketConnector connector;
建立连接并注册消息回调:
WebSocketClientConnection connection = connector
.baseUri(serverUrl)
.executionModel(BasicWebSocketConnector.ExecutionModel.NON_BLOCKING)
.onTextMessage((c, m) -> {
// 处理服务端消息
})
.connectAndAwait();
⚠️ WebSocket 是全双工异步协议,必须注册回调处理服务端消息
发送消息示例:
connection.sendTextAndAwait("Hello, World!");
❌ 连接对象非线程安全,避免多线程并发写入
4.2 增强型客户端
类似服务端接口,可通过注解创建结构化客户端:
@WebSocketClient(path = "/json")
class RichWebsocketClient {
// 客户端实现
}
使用相同注解处理事件:
@OnTextMessage
void onMessage(String message, WebSocketClientConnection connection) {
// 处理消息
}
参数规则与服务端一致,但连接对象类型为
WebSocketClientConnection
通过 WebSocketConnector<T>
建立连接:
@Inject
WebSocketConnector<RichWebsocketClient> connector;
WebSocketClientConnection connection = connector
.baseUri(serverUrl)
.connectAndAwait();
获取客户端实例:
@Inject
Instance<RichWebsocketClient> clients;
⚠️ 客户端实例仅在特定上下文可用,需注意异步事件顺序
5. 总结
本文介绍了 Quarkus 中 websockets-next
扩展的基础用法,包括服务端接口和客户端实现。虽然只覆盖了基本功能,但该库已能处理多种高级场景。对于需要高性能 WebSocket 通信的 Quarkus 应用,这是一个值得尝试的现代化解决方案。