前言

在现代应用架构中,实时通信已成为不可或缺的一环。无论是社交应用、在线客服、企业协作还是物联网指令下发,长连接与实时消息推送都是核心能力。本文将基于 Spring Boot 3.5.12 + Netty 4.1.100,手把手带你搭建一个生产级的多身份实时聊天系统

该系统支持普通用户、企业、平台管理员三种角色,提供点对点聊天与分组广播(通知全体用户/全体企业/全员)功能,并通过 JWT 鉴权、心跳保活、广播权限开关、在线统计等机制,确保安全与可运维性。最终单机可轻松支撑 10 万+ 并发长连接。

 完整代码https://github.com/W-DAFU/SpringDome17Netty.git 

一、系统设计

1.1 核心需求

  • 区分三种用户身份:USER(普通用户)、ENTERPRISE(企业)、PLATFORM(平台管理员)

  • 支持点对点聊天(任意身份互聊)

  • 支持广播:通知所有用户、通知所有企业、通知所有人

  • 广播权限可配置,默认仅平台管理员可发

  • 支持多媒体消息类型(文本、图片、视频、卡片)

  • JWT 安全认证

  • 在线人数统计与分类查询

  • 高性能,单机 10 万+ 连接

1.2 架构概览

采用 Spring Boot 管理 Bean 与生命周期 + Netty 负责网络通信 的架构:

  • Spring 容器负责 Netty 服务器的启动、关闭,以及各类依赖注入

  • Netty 使用主从 Reactor 线程模型,结合 Epoll(Linux)或 NIO 实现高性能 IO

  • 连接鉴权通过 WebSocket 握手阶段的 URL 参数 token 完成

  • 消息路由由内部 Dispatcher 根据消息类型分发

  • 连接存储使用 ConcurrentHashMap + ChannelGroup 组合保证并发安全

二、项目结构

src/main/java/org/dafu/springdome17netty/
├── config
│   └── GlobalCorsConfig.java          # 跨域配置
├── chat
│   ├── config
│   │   ├── BroadcastProperties.java   # 广播权限配置
│   │   └── NettyProperties.java       # Netty 参数配置
│   ├── constant
│   │   └── AttributeKeys.java         # Channel 属性 Key
│   ├── handler
│   │   ├── AuthHandshakeHandler.java  # 握手认证
│   │   └── ChatMessageHandler.java    # 业务消息与心跳
│   ├── initializer
│   │   └── WebSocketChannelInitializer.java  # Channel 初始化器
│   ├── lifecycle
│   │   └── ChatWebSocketServer.java   # Netty 生命周期管理
│   ├── model
│   │   ├── ChatMessage.java
│   │   ├── UserInfo.java
│   │   └── UserType.java
│   ├── repository
│   │   └── UserChannelRepository.java # 连接仓库
│   ├── routing
│   │   └── MessageDispatcher.java     # 消息路由与权限
│   └── util
│       └── JwtUtils.java
├── controller
│   └── MonitorController.java         # 监控端点
└── SpringDome17NettyApplication.java

三、关键技术实现详解

3.1 身份体系设计

用户类型枚举 UserType

  • USER:普通用户

  • ENTERPRISE:企业

  • PLATFORM:平台管理员

企业 ID 约定以 ent_ 开头,便于路由区分,普通用户无前缀要求。

3.2 JWT 连接认证

客户端在 WebSocket 连接时携带参数 ?token=xxx。服务端通过 AuthHandshakeHandler 拦截 HTTP 握手请求,校验 JWT 后提取用户信息并绑定到 Channel 属性上,然后放行协议升级。

关键代码片段:

UserInfo userInfo = jwtUtils.verify(token);
ctx.channel().attr(AttributeKeys.USER_INFO).set(userInfo);
request.setUri("/ws"); // 去掉 token,交给 WebSocket 握手处理器
ctx.fireChannelRead(request.retain());

若校验失败,直接返回 401 并关闭连接。

3.3 连接存储与分组管理

UserChannelRepository 采用两个 ConcurrentHashMap 分别存储用户和企业(平台管理员与用户合并存储在 userChannelMap),同时使用 ChannelGroup 维护全量连接。

主要方法:

  • add/remove:上下线管理(同 ID 踢旧连)

  • findByUserId/findByEnterpriseId:精确查找

  • getAllUserChannels/getAllEnterpriseChannels/getAllChannels:分组或全量获取

  • getOnlineCountByType:按类型统计在线人数

均具备 O(1) 读写性能,支撑 10 万+ 连接无压力。

3.4 消息路由与权限控制

MessageDispatcher 根据消息 type 字段进行分发:

消息类型 说明 权限
SINGLE 点对点聊天 所有身份均可
BROADCAST_USER 通知所有用户 仅 PLATFORM(可配)
BROADCAST_ENTERPRISE 通知所有企业 仅 PLATFORM(可配)
BROADCAST_ALL 全员广播 仅 PLATFORM(可配)

广播权限由 BroadcastProperties 读取配置项 broadcast.allowed-roles 控制,支持角色名列表或 ALL 全部放开。

单聊路由时,通过目标 ID 前缀 ent_ 判断存储位置,查找对应 Channel 进行写入;若目标不在线,可扩展存储离线消息(示例中仅打印日志)。

3.5 心跳与连接保护

ChatMessageHandler 结合 Netty 的 IdleStateHandler 实现读空闲检测(默认 300 秒),超时即关闭连接。前端可定时发送轻量 PING 帧保活。

3.6 生命周期集成

ChatWebSocketServer 实现 SmartLifecycle 并设置最高相位(Integer.MAX_VALUE),确保在 Spring 容器完全初始化后(所有 Bean 就绪)启动;容器关闭时自动调用 stop() 优雅退出。

启动时自动根据 OS 选择 Epoll(Linux)或 NIO,配置内存池、连接队列等参数以优化性能。

3.7 媒体类型扩展

消息体 ChatMessage 包含 contentType 字段,支持 TEXTIMAGEVIDEOCARD 等,客户端可据此渲染不同 UI 组件。若无该字段,默认为 TEXT,向后兼容。

四、配置文件一览

application.yml 核心配置:

server:
  port: 8080

netty:
  websocket:
    port: 9090
    path: /ws
    boss-threads: 1
    worker-threads: 16
    max-frame-size: 65536
  idle:
    reader-idle-seconds: 300

jwt:
  secret: <your-secret-key>

broadcast:
  allowed-roles: PLATFORM   # 可改为 PLATFORM,ENTERPRISE 或 ALL

五、接口说明

5.1 获取 Token

GET /monitor/token?userId=admin1&type=PLATFORM&expireMs=86400000

用于测试时快速生成 JWT。

5.2 在线统计

GET /monitor/online

返回示例:

{
    "USER": 158,
    "ENTERPRISE": 42,
    "PLATFORM": 2,
    "TOTAL": 202
}

六、前端接入(Uniapp 示例)

配套提供了完整 Uniapp 前端,包含登录页(身份选择)与聊天界面。核心逻辑:

  • 通过 API 获取 Token,保存到本地

  • 使用 uni.connectSocket 建立 WebSocket 连接,URL 带上 token 参数

  • 仅 PLATFORM 角色可见广播按钮

  • 消息根据 contentType 展示不同内容(文本、图片、视频等)

前端只需修改 api.js 与 websocket.js 中的后端地址即可对接。

七、性能优化与压测建议

  • Netty 调优
    使用 Epoll 模型、PooledByteBufAllocator 内存池、合理设置 Worker 线程数(建议 CPU 核数 ×2)。

  • JVM 参数
    -Xms4g -Xmx4g -XX:MaxDirectMemorySize=2g -XX:+UseG1GC

  • OS 限制
    提高文件描述符(ulimit -n 1000000)、调整内核参数(somaxconn、tcp_max_syn_backlog 等)。

  • 压测工具
    可使用 JMeter WebSocket 插件或自定义客户端模拟 10 万连接,验证心跳与消息投递。

八、扩展展望

当前为单机版本,若需水平扩展可引入 Redis Pub/Sub 或 RocketMQ 作为消息桥,将连接状态存储于 Redis(用户→节点映射),实现跨节点消息路由。架构已预留扩展接口,轻松升级为分布式聊天集群。

九、总结

本文从零开始,完整演示了基于 Spring Boot 3 + Netty 的高性能多身份聊天系统搭建过程,涵盖了认证、路由、权限、心跳、监控等关键环节。代码注释清晰,可直接复制运行。希望能为你在实时通信场景下的技术选型与落地提供参考。

完整代码https://github.com/W-DAFU/SpringDome17Netty.git。如有疑问,欢迎在评论区交流。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐