生产可用的 Java 17 游戏服务器框架(多模块 Maven 工程骨架)
- common: 公共模块,承载工具类、SPI 可插拔接口、协议与通用组件
- services: 业务服务聚合模块
- gateway: 网络网关服务
- login: 登录鉴权服务
- logic: 核心逻辑服务
- scene: 场景/地图服务
- rank: 排行榜服务
- chat: 聊天服务
- pay: 支付服务
- launcher: 一键启动管理模块
- JDK 17+
- Maven 3.8+
# 编译项目
mvn -q -DskipTests package
# 运行代码质量检查
mvn -DskipTests verify- 遵循 阿里巴巴 Java 开发规约 (P3C)
- 使用 Checkstyle 进行代码规范检查
- 使用 Spotless 进行代码格式化 (基于 google-java-format)
- 统一包命名、类命名、注释完整
# 代码格式化
mvn spotless:apply
# 代码规范检查
mvn checkstyle:check
# 完整验证 (提交前必须执行)
mvn -DskipTests verify请阅读 CONTRIBUTING.md 了解详细的开发规范和流程。
每次 Push 和 Pull Request 都会自动执行:
- ✅ 代码编译验证
- ✅ Spotless 格式检查
- ✅ Checkstyle 代码规范检查
- ✅ 单元测试执行 (如有)
本仓库将逐步通过以下 PR 完善:
- ✅ PR-02: 代码规范与 CI 门禁 (Checkstyle、Spotless)
- ✅ PR-03: SPI 可插拔组件框架
- ✅ PR-04: 日志与观测基础设施
- ✅ PR-05: 配置中心与环境分层
- ⏳ PR-06: 协议层 (Protobuf) 与消息封装
- ⏳ PR-07: Netty 网关最小可运行版本
- ⏳ PR-08: 数据层抽象与缓存集成
- ⏳ PR-09: 微服务注册发现与扩展
- ⏳ PR-10: 监控指标与健康检查
- ⏳ PR-11: 部署脚本与容器化支持
game-frame 提供了轻量级的配置中心能力,支持多环境分层加载与覆盖,满足开发、测试、生产等不同环境的配置需求。
- 多环境支持: 支持 dev/test/prod 三种标准环境,默认为 dev
- 分层覆盖: 配置按优先级覆盖,确保灵活性和安全性
- 环境变量映射: 支持通过环境变量覆盖配置,便于容器化部署
- 占位符解析: 支持
${key:default}语法的配置引用 - 零依赖实现: 仅使用 JDK 标准能力,无需引入第三方库
环境选择按以下优先级顺序:
-
JVM 系统属性(最高优先级)
java -Denv=prod YourApp
-
环境变量
export GAME_ENV=prod java YourApp -
默认环境:dev
配置文件统一放置在 common/src/main/resources/config/ 目录下:
common/src/main/resources/config/
├── application.properties # 默认配置(所有环境共享)
├── application-dev.properties # 开发环境配置
├── application-test.properties # 测试环境配置
└── application-prod.properties # 生产环境配置
配置值按以下优先级覆盖(数字越大优先级越高):
1. 默认配置文件 (application.properties)
↓
2. 环境配置文件 (application-{env}.properties)
↓
3. JVM 系统属性 (-Dkey=value)
↓
4. 环境变量 (GAME_*) ← 最高优先级
环境变量到配置键的映射规则:
- 必须以
GAME_开头 - 移除前缀后转换为小写
- 下划线
_转换为点号.
映射示例:
GAME_SERVER_PORT=9000 → server.port=9000
GAME_DATABASE_URL=xxx → database.url=xxx
GAME_LOGGING_LEVEL_ROOT=WARN → logging.level.root=WARNimport com.game.common.config.Config;
import com.game.common.config.PropertyResolver;
// 加载当前环境配置(自动检测环境)
Config config = PropertyResolver.load();
// 加载指定环境配置
Config config = PropertyResolver.load("prod");
// 读取配置值
String appName = config.getString("app.name");
int serverPort = config.getInt("server.port", 8080);
boolean debugEnabled = config.getBoolean("debug.enabled", false);# 编译项目
mvn -q -DskipTests package
# 默认环境运行(dev)
java -cp "launcher/target/classes:common/target/classes" com.game.launcher.LauncherConfigDemo
# 指定生产环境
java -Denv=prod -cp "launcher/target/classes:common/target/classes" com.game.launcher.LauncherConfigDemo
# 环境变量覆盖端口
GAME_SERVER_PORT=9000 java -cp "launcher/target/classes:common/target/classes" com.game.launcher.LauncherConfigDemo当前实现保留了良好的扩展空间,未来可以考虑:
- YAML/TOML 支持: 扩展支持更现代的配置格式
- 集中式配置: 集成 Nacos、Consul 等配置中心
- 热加载机制: 支持配置文件变更时自动重载
- 配置加密: 敏感配置的加密存储和解密
- 配置验证: 配置项的类型和取值范围验证
- 多数据源: 支持数据库、远程 HTTP 等配置源
game-frame 提供了轻量级的可插拔组件框架,支持通过 Java SPI 机制自动装配组件。开发者可以轻松扩展和集成自定义业务组件。
组件生命周期:每个组件都遵循 init() -> start() -> stop() 的标准生命周期
init(): 初始化资源、读取配置、建立依赖关系start(): 启动服务、开始监听、启动后台线程stop(): 停止服务、释放资源、清理缓存
组件顺序:通过 getOrder() 方法定义装配优先级,数值越小优先级越高
- 初始化和启动:按 order 从小到大执行
- 停止:按 order 从大到小执行(逆序)
package com.game.business.component;
import com.game.common.component.Component;
import com.game.common.component.ComponentException;
public class MyBusinessComponent implements Component {
@Override
public int getOrder() {
return 200; // 数值越小优先级越高,建议使用100的倍数
}
@Override
public void init() throws ComponentException {
// 组件初始化逻辑
}
@Override
public void start() throws ComponentException {
// 组件启动逻辑
}
@Override
public void stop() throws ComponentException {
// 组件停止逻辑
}
}在 src/main/resources/META-INF/services/ 目录下创建文件:
com.game.common.component.Component
文件内容为组件的完整类名:
com.game.business.component.MyBusinessComponent
推荐的 order 值分配:
- 0-99: 核心基础组件(日志、配置、监控等)
- 100-199: 中间件组件(数据库、缓存、消息队列等)
- 200-299: 网络组件(网关、RPC、协议处理等)
- 300-399: 业务基础组件(认证、权限、通用服务等)
- 400+: 具体业务组件
mvn -q -DskipTests package# 编译 launcher 模块
mvn -q -DskipTests -pl launcher -am package
# 在 IDE 中运行 LauncherSpiDemo.main() 方法
# 或使用命令行:
java -cp "launcher/target/classes:common/target/classes" com.game.launcher.LauncherSpiDemo演示程序会自动:
- 扫描并加载所有 SPI 组件
- 按优先级顺序初始化和启动组件
- 注册 JVM 关闭钩子确保优雅停止
- 输出详细的生命周期日志
- 包命名规范: 组件建议放在
*.component包下,实现类放在*.component.impl包下 - 异常处理: 组件方法应抛出
ComponentException,提供清晰的错误信息 - 日志记录: 使用 SLF4J 统一日志门面,支持结构化日志和 traceId 追踪
- 资源管理: 确保在
stop()方法中正确释放所有资源 - 线程安全: 组件应设计为线程安全,支持并发访问
game-frame 提供了统一的日志门面和轻量级观测能力,支持结构化日志、分布式追踪和 JVM 指标监控。
框架采用 SLF4J 作为统一日志门面,默认使用 Logback 实现:
- SLF4J 2.0.13: 统一日志接口,支持参数化日志和 MDC
- Logback 1.5.6: 高性能日志实现,支持配置热加载
框架提供开箱即用的结构化日志配置 (common/src/main/resources/logback.xml):
%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level [%X{traceId:-}] %logger{36} - %msg%n
输出示例:
2025-09-12 02:35:48.757 [main] INFO [b6518f83daa0489b] c.game.launcher.LauncherLoggingDemo - 程序启动
2025-09-12 02:36:18.907 [metrics-reporter] INFO [] c.g.c.observability.MetricsReporter - jvm.metrics heapUsedMB=9 heapCommittedMB=254 heapMaxMB=4000 threadCount=7
使用 TraceContext 工具类进行分布式追踪:
// 生成新的 traceId
String traceId = TraceContext.generateTraceId();
// 放入 MDC,当前线程的所有日志都会包含此 traceId
TraceContext.put(traceId);
// 获取当前线程的 traceId
String currentTraceId = TraceContext.get();
// 清理 MDC,防止线程复用污染
TraceContext.clear();使用 MetricsReporter 进行轻量级 JVM 监控:
// 创建指标上报器(可配置采集周期)
MetricsReporter reporter = new MetricsReporter(Duration.ofSeconds(30));
// 启动定期采集
reporter.start();
// 应用关闭时停止采集
reporter.stop();可配置项:
- 采集周期:默认 30 秒,最小 5 秒
- 输出指标:堆内存使用/提交/最大值、线程数量
运行日志与观测功能演示:
# 编译项目
mvn -q -DskipTests -pl launcher -am package
# 在 IDE 中运行 LauncherLoggingDemo.main() 方法
# 或使用命令行:
mvn dependency:copy-dependencies -pl launcher
java -cp "launcher/target/classes:launcher/target/dependency/*" com.game.launcher.LauncherLoggingDemo项目可通过自定义 logback.xml 覆盖默认配置:
- 在具体模块的
src/main/resources/下创建logback.xml - 参考
common模块的默认配置进行定制 - 支持多种 Appender:Console、File、RollingFile、Async 等
本项目采用 MIT 许可证 - 详见 LICENSE 文件