项目工程结构设计
概述
游戏服务器的工程结构直接影响协作效率与维护成本。核心是多模块划分:把公共依赖、协议定义、网关接入、业务逻辑、数据访问拆成独立模块,边界清晰、依赖单向。本文讲透 Maven/Gradle 多模块设计。
一、为什么需要多模块
1.1 单模块的痛点
单模块问题:
代码全部堆在一起
协议改动影响全局编译
依赖关系混乱
无法独立测试/复用
多模块价值:
边界清晰(依赖单向)
协议独立(前后端共享)
构建分层(按需编译)
复用清晰(公共模块)1.2 模块化原则
原则:
依赖单向(上层依赖下层,不反向)
接口稳定(模块间通过接口通信)
职责单一(每个模块一个职责)
可独立编译测试二、Maven 多模块
2.1 父 POM 结构
父工程(game-server-parent):
pom.xml(聚合 + 依赖管理)
子模块:
game-server-common(公共)
game-server-protocol(协议)
game-server-gateway(网关)
game-server-logic(逻辑)
game-server-db(数据)
game-server-start(启动)父 POM 关键配置:
<packaging>pom</packaging>
<modules> 列出所有子模块 </modules>
<dependencyManagement> 统一版本 </dependencyManagement>2.2 依赖方向
依赖图(上层依赖下层):
game-server-start(启动装配)
├── gateway
├── logic
├── protocol
└── common
gateway → protocol、common
logic → protocol、db、common
db → common
protocol → common
注意:logic 不依赖 gateway(解耦)2.3 Maven 命令
常用命令:
mvn clean install # 全量构建
mvn -pl game-server-logic # 只构建某模块
mvn -am # 连带依赖模块
mvn dependency:tree # 查看依赖树三、Gradle 多模块(备选)
3.1 Gradle 结构
settings.gradle:
rootProject.name = 'game-server'
include 'game-server-common'
include 'game-server-protocol'
...
根 build.gradle:公共配置
各模块独立 build.gradle3.2 Gradle vs Maven
| 维度 | Maven | Gradle |
|---|---|---|
| 配置 | XML | Groovy/Kotlin DSL |
| 性能 | 中 | 快(增量/守护进程) |
| 灵活性 | 低 | 高 |
| 生态 | 极成熟 | 成熟 |
| 学习曲线 | 低 | 中 |
选型建议:
团队熟悉 → Maven(保守稳妥)
追求构建速度 → Gradle(现代选择)
本项目示例以 Maven 为主四、模块职责边界
4.1 game-server-common(公共模块)
职责:
通用工具(时间/随机/字符串)
常量定义
异常体系
通用模型(Result 包装)
日志封装
依赖:
仅第三方基础库(无业务依赖)4.2 game-server-protocol(协议模块)
职责:
Protobuf 定义与生成代码
消息 Opcode 常量
消息枚举/结构体
编解码工具
重要性:
与客户端共享(协议先行)
网关与逻辑都依赖它
协议改动集中在这协议模块内容:
src/main/proto/*.proto(原始定义)
生成的 Java 类(protoc 生成)
编解码器(Encoder/Decoder)4.3 game-server-gateway(网关模块)
职责:
Netty 服务器启动
连接管理(Session)
协议编解码(粘包拆包)
心跳检测
消息路由(转发到逻辑层)
鉴权(Token 校验)
注意:
网关不含业务逻辑
只做接入与转发4.4 game-server-logic(逻辑模块)
职责:
玩家/房间/匹配/社交/对战等业务
房间状态机
数据变更(调用 db 模块)
广播(调用网关发送接口)
注意:
核心玩法核心所在
与网关通过接口解耦4.5 game-server-db(数据模块)
职责:
MySQL DAO/Mapper
Redis 操作封装
实体对象
事务管理
注意:
只做数据访问
不含业务规则4.6 game-server-start(启动模块)
职责:
Spring Boot 启动类
装配所有模块
主配置(application.yml)
初始化(Netty 启动等)
作用:
聚合入口
运行时装配五、模块间通信设计
5.1 网关与逻辑解耦
方式一:接口注入
网关定义 MessageDispatcher 接口
逻辑实现分发逻辑
方式二:事件总线
网关发事件,逻辑监听
方式三:消息队列(分布式)
网关 → MQ → 逻辑(异步解耦)推荐(单体阶段):
网关 Handler 收到消息
→ 通过 MessageRouter(接口)
→ 逻辑层 Dispatch
实现解耦、可替换5.2 数据访问边界
边界规则:
逻辑不直接写 SQL
逻辑调用 db 模块接口
db 返回实体/DTO
好处:
数据层可替换
事务集中管理
测试可 mock六、配置与资源管理
6.1 配置分层
配置位置:
game-server-start/resources:
application.yml(主配置)
application-dev.yml(开发)
application-prod.yml(生产)
公共配置:
日志(logback.xml)
数据库连接
Netty 端口6.2 资源隔离
实践:
各模块自己的资源放自己目录
启动模块统一加载
敏感配置走环境变量/配置中心七、常见问题
7.1 循环依赖
现象:
logic 依赖 gateway,gateway 又依赖 logic
解决:
提取公共接口模块
依赖方向单向化
网关只依赖"分发接口"7.2 协议模块被频繁改
现象:
前后端都在改 .proto
协议模块频繁构建
解决:
协议独立模块(减少影响面)
版本管理(协议版本)
变更评审7.3 模块拆太细
问题:
模块过多 → 构建慢、管理难
建议:
按"高内聚低耦合"拆
初期 5-6 个模块足够
按需再拆(如单独匹配模块)八、小结
工程结构设计的核心是依赖单向 + 边界清晰。推荐 Maven 六模块:common(公共)、protocol(协议)、gateway(网关)、logic(逻辑)、db(数据)、start(启动)。协议独立成模块实现前后端共享,网关与逻辑通过接口解耦保证可扩展。结构对了,多人协作与后续演进都会顺畅很多。