easy-notification 使用文档
easy-notification 是基于 easy-socketio 的独立部署通知中间件(fatjar)。服务端提供三级房间协议(
user:{userCode}/product:{code}/broadcast)、握手鉴权 SPI、Redis 集群横向扩容;业务侧通过NotificationPusher推送事件。
1. 构建与启动
mvn package -pl middlewares/easy-notification
# 单机模式
java -jar middlewares/easy-notification/target/easy-notification-1.2.1-SNAPSHOT.jar
# 集群模式(多实例 + Redis 房间同步)
java -jar easy-notification.jar \
--socketio.cluster.enabled=true \
--spring.data.redis.host=192.168.x.x
启动成功标志:
SocketIO server started at port: 9092
Started NotificationApplication in 2.4 seconds
2. 配置项
| 配置项 | 默认值 | 说明 |
|---|---|---|
socketio.enabled | true(fatjar 内置) | 服务开关;嵌入到业务服务时默认 false,需显式开启 |
socketio.hostname | 0.0.0.0 | 监听地址 |
socketio.port | 9092 | 服务端口(无 web 容器,这就是唯一端口) |
socketio.namespace | / | 命名空间;推送与监听统一经 resolveNamespace 处理 |
socketio.auth-required | false | true 时握手未携带有效 token 拒绝连接 |
socketio.cluster.enabled | false | 集群开关;开启后房间经 Redis Pub/Sub 跨节点同步 |
spring.data.redis.* | localhost:6379 | 集群模式的 Redis 连接(标准 Spring Boot 配置) |
3. 客户端接入协议
// socket.io client v4(EIO4)
const socket = io("http://host:9092", { auth: { token: "xxx" } });
// 订阅产品房间(服务端经 AuthListener.canSubscribe 校验)
socket.emit("subscribe", { room: "product:PRD-001" });
socket.emit("unsubscribe", { room: "product:PRD-001" });
// 收推送
socket.on("order.paid", (data) => { ... });
// chat 示例(房间内广播)
socket.emit("chat", { room: "product:PRD-001", nickname: "张三", content: "hello" });
socket.on("chat", (msg) => { ... });
握手成功后自动加入:user:{userCode}(鉴权通过)+ broadcast(全员);匿名连接只进 broadcast。
4. 服务端推送
嵌入模式(业务服务与通知同进程):业务服务引入 io.matrix:easy-notification 依赖,直接注入推送门面:
@Autowired NotificationPusher pusher;
pusher.toUser("u-1001", "order.paid", payload); // 个人
pusher.toProduct("PRD-001", "status", payload); // 产品房间订阅者
pusher.broadcast("notice", payload); // 全员
pusher.toRoom("custom-room", "event", payload); // 自定义房间
独立部署模式:通知中心单独跑 fatjar,业务侧推送经领域事件桥接(业务发布 NotificationEvt → 通知中心订阅 → NotificationPusher 投递)——桥接 handler 待建,见 DESIGN §七。
5. 鉴权接入
提供 AuthListener Bean 即接入(组件层 SPI):
@Component
public class PulseAuthListener implements AuthListener {
@Override
public String authenticate(String token) {
return authorizeService.verify(token); // 返回 userCode,失败返回 null
}
@Override
public boolean canSubscribe(String userCode, String room) {
return roomService.hasPermission(userCode, room);
}
}
fatjar 内无实现时保持 auth-required: false,客户端以 anonymous 进 broadcast 房间。
6. 注意事项
| 项 | 说明 |
|---|---|
| 旧客户端协议迁移 | 旧 operations 事件(join/leave)已废弃,改用 subscribe/unsubscribe;旧 action 事件已删除 |
| 集群序列化器 | 集群模式 Pub/Sub 消息经 RedisTemplate 序列化,需保留类型信息(JDK 序列化或带 defaultTyping 的 Jackson),否则跨节点反序列化失败 |
| 默认 JDK 17 | fatjar 按框架统一 JDK17 编译,运行环境需 JDK 17+ |
| 端口 | 无 web 容器,server.port 无效,只有 socketio.port |
7. 常见问题
Q:为什么业务服务嵌入模式也要依赖 easy-socketio? easy-notification 只含业务层,服务器装配/房间协议/Redis 分布式全部由 easy-socketio 提供,版本(netty-socketio 2.0.14)经它传递,请勿自行声明 netty-socketio 版本。
Q:集群模式多实例下,推送会重复吗?
不会。RedisStoreFactory 的 Pub/Sub 消息带 nodeId,本节点事件不回环;toUser 房间同步后各实例都能命中本机连接,单条消息只投一次。
Q:如何自定义 namespace?
配置 socketio.namespace=/devops 即可,推送与监听自动对齐;客户端连接 URL 需带同名 namespace。