这是一个用于学习、演示和逐步扩展的推荐系统工程,当前包含 3 个模块:
backed:在线服务模块recommendation-trainer:离线训练模块example:教学示例模块
技术栈:
Java 17Spring Boot 3.5KafkaSpark 4.0MySQLSpring AI
在线服务,主要负责:
- Web API 暴露
- Kafka 事件接入
- Spark Streaming 行为流处理
- 用户偏好聚合
- 在线召回读取
- AI 对话接口
默认端口:
8922
离线训练服务,主要负责:
- 基于
user_item_preference做 ALS 训练 - 生成
user_cf_recall - 发布
recommendation_model_version - 清理旧版本召回数据
默认端口:
8923
教学示例模块,专门放“可运行、可观察、可扩展”的学习型代码。
默认端口:
8924
当前 example 模块里有 2 个可运行示例:
位置:
- JvmMemoryLearningService.java
- JvmMemoryLearningController.java
这个示例能学什么:
- JVM 内存划分
- Heap / Non-Heap / Direct Buffer 的基本观察
- GC Roots
- 可达性分析
- 标记清理的基本过程
- 为什么纯 mark-sweep 会有碎片问题
可访问接口:
GET /api/examples/jvm/layoutGET /api/examples/jvm/gc/mark-sweepGET /api/examples/jvm/overview
位置:
- PaymentOrder.java
- PaymentOrderRepository.java
- JdbcPaymentOrderRepository.java
- PaymentApplicationService.java
- PaymentController.java
这个示例能学什么:
- 为什么支付必须有幂等键
- 为什么状态机必须是单向流转
- 为什么
UNPAID -> PAYING -> SUCCESS / CLOSED比“只有成功/失败”更真实 - 为什么真正的幂等护栏最终要落在数据库条件更新上
- 如何用
Repository + ApplicationService + Controller搭一个最小可运行支付链
当前已实现的能力:
- 创建订单
- 幂等创建
- 发起支付
- 回写支付成功
- 关闭订单
- 查询订单状态
可访问接口:
GET /api/examples/payments/demoPOST /api/examples/payments/ordersPOST /api/examples/payments/orders/{orderNo}/startPOST /api/examples/payments/orders/{orderNo}/successPOST /api/examples/payments/orders/{orderNo}/closeGET /api/examples/payments/orders/{orderNo}
recommendation_system/
├─ pom.xml
├─ backed/
├─ recommendation-trainer/
├─ example/
└─ docs/
mvn -pl backed -DskipTests spring-boot:runmvn -pl recommendation-trainer -DskipTests spring-boot:runmvn -pl example -DskipTests spring-boot:run这两个模块默认依赖 MySQL。
可以先启动本地 MySQL:
docker run -d \
--name mysql \
-p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root \
-e MYSQL_DATABASE=recommendation \
--restart unless-stopped \
mysql:8.4相关 SQL 目录:
backed/src/main/resources/database/recommendation-trainer/src/main/resources/database/
example 模块默认使用 H2 内存数据库,不需要手工建库。
启动时会自动执行:
- schema.sql
- data.sql
H2 控制台地址:
http://localhost:8924/h2-console
JDBC URL:
jdbc:h2:mem:exampledb
GET /api/examples/payments/demoPOST /api/examples/payments/orders
Content-Type: application/json{
"orderNo": "PAY_NEW_20260320_001",
"idempotencyKey": "IDEMP_NEW_20260320_001",
"userId": 1001,
"productCode": "VIP_MONTH",
"amountFen": 9900
}POST /api/examples/payments/orders/PAY_NEW_20260320_001/start
Content-Type: application/json{
"idempotencyKey": "IDEMP_NEW_20260320_001"
}POST /api/examples/payments/orders/PAY_NEW_20260320_001/success
Content-Type: application/json{
"channelTradeNo": "WX202603200099",
"paidAt": "2026-03-20T16:30:00"
}GET /api/examples/payments/orders/PAY_NEW_20260320_001data.sql 已经预置 3 笔订单,方便直接测试:
PAY_DEMO_SUCCESS_001PAY_DEMO_PAYING_001PAY_DEMO_CLOSED_001
它们分别用于观察:
- 已成功订单的幂等回写
- 支付中订单的查询与补偿入口
- 已关闭订单的非法流转拦截
example 模块接下来最自然的扩展是:
- 接入
Kafka,模拟支付成功消息重复投递 - 接入
Redisson,演示按订单号加分布式锁 - 增加“支付中超时扫描”的补偿任务
- 进一步贴近真实支付系统的幂等闭环