为什么要做这个项目#

在实际工作中,每当要推一套新的技术方向时,团队最常遇到的问题不是"知不知道这个技术",而是——“这东西跑起来是什么样子?出了问题怎么排查?和现有的模块能不能配合?”

光读官方文档和博客往往很难回答这些问题。于是我决定做一个尽量完整跑通的 POC 项目——一个电商平台原型,把当时想亲手验证的技术选型尽量放进同一个可运行工程里,看看它们在微服务场景中能不能协同工作。

这个项目就是 Shop Platform,也是本系列文章的主角。

2026-04 实践更新 目前主线仓库已经完成一批最初文章发布时仍在演进中的平台项:auth-serverRS256 + JWKSapi-gatewayJWKS 校验 + Redisson Lua 限流buyer-bff / seller-bff全量 @HttpExchange typed clients、镜像构建 → AppCDS 三阶段构建。还刻意保持延期的,主要是 DistributedLockExecutor 抽象、搜索增强、AI 推荐等下一阶段能力。

系列会围绕几个方向展开:

  • 总览(本文):项目背景、整体架构、技术栈速览
  • 各层专题:API 网关、认证信任链、BFF 聚合、领域服务、事件总线、可观测、活动引擎……
  • 工程实践:ArchUnit 架构测试、Maven Archetype 脚手架、Feature Toggle、KMP 跨端……

项目是什么#

Shop Platform 是一个云原生微服务电商平台 POC,支持:

  • 买家/游客浏览商品、加购物车、结账下单
  • 卖家管理商品、订单、促销
  • 钱包真实货币支付(Stripe 接入)
  • 积分、优惠券、活动(签到/抽奖/集卡/虚拟养成)
  • 搜索、Webhook 开放平台、订阅续费

项目目的是技术验证,不是生产级业务实现。功能覆盖面是为了让各个技术模块都能找到真实的应用场景,而不是为了做完整的业务产品。


整体架构#

整体分为五个层次:

flowchart TD Client["客户端层
Buyer Portal / Buyer App / Seller Portal"] Gateway["边缘层: API Gateway
JWT 校验 · Trusted Headers · Redis Lua 限流 · Canary 灰度"] BFF["聚合层: Buyer BFF ↔ Seller BFF
Virtual Threads + Resilience4j"] Domain["领域服务层
profile · marketplace · order · wallet
promotion · loyalty · activity · search
notification · webhook · subscription"] Infra["基础设施层
MySQL 8.4 · Kafka 3.9 · Redis 7.4 · Meilisearch 1.12 · Garage S3"] Obs["可观测层
Micrometer · OTel Collector · Tempo · Loki
Grafana · Prometheus · Pyroscope"] Client -->|"HTTPS"| Gateway Gateway -->|"Trusted Headers"| BFF BFF --> Domain Domain --> Infra Domain -.->|"metrics · traces · logs"| Obs BFF -.->|"metrics · traces · logs"| Obs Gateway -.->|"metrics · traces · logs"| Obs

流量路由#

路径前缀 目标
/buyer/** buyer-portal(Kotlin SSR,SEO/游客模式)
/buyer-app/** buyer-app(KMP WASM SPA,交互式购物体验)
/seller/** seller-portal(部署单元名;内容来自 frontend/kmp/seller-app
/api/buyer/** buyer-bff(聚合领域服务)
/api/seller/** seller-bff(聚合领域服务)
/api/loyalty/** loyalty-service
/api/activity/** activity-service
/api/webhook/** webhook-service
/api/subscription/** subscription-service
/auth/** auth-server
/public/** 白名单,无需鉴权

Gateway 完成 JWT 校验后,把身份信息(Buyer-Id、Username、Roles、Portal)以 Trusted Headers 形式注入请求,下游服务直接信任这些 header,不需要重复解析 token。

前端架构演进#

项目采用渐进式前端策略,根据不同场景选择最适合的技术栈:

flowchart TD BP["Buyer Portal
Kotlin + Thymeleaf SSR"] BA["Buyer App
KMP WASM SPA"] SP["Seller Portal
KMP WASM via seller-portal"] BP --> L["/buyer/login 登录页"] BP --> R["/buyer/register 注册页"] BP --> C["/buyer/catalog 商品浏览 SEO"] BA --> D["/buyer-app/ 购物车 · 结账 · 订单追踪"] SP --> E["/seller/ 商品 · 订单 · 促销管理"]

KMP(Kotlin Multiplatform)模块采用功能模块化设计:

KMP 模块 职责
core 网络层、状态管理、路由、主题系统
feature-auth 认证流程(JWT、Google/Apple/OTP 登录)
feature-cart 购物车管理(游客/登录态统一)
feature-marketplace 商品浏览、搜索、筛选
feature-order 订单创建、追踪、历史
feature-profile 用户档案、地址簿
feature-promotion 优惠券、活动展示
feature-wallet 钱包余额、充值、Stripe 支付
ui-shared 通用 UI 组件库
buyer-app 买家应用组装(WASM)
seller-app 卖家应用组装(WASM)

这种拆分让同一套 feature-* 模块可以复用到 WASM Web、Android 和 iOS 客户端;对一个技术验证型 POC 来说,这种组织方式比为每个端单独复制业务逻辑更容易观察演进成本。


服务清单#

服务 语言 职责
api-gateway Java 25 统一入口、JWT 校验、限流、灰度
auth-server Java 25 JWT 签发、Google/Apple/OTP 登录、游客 token
buyer-bff Java 25 买家聚合、游客购物流、结账编排
seller-bff Java 25 卖家工作台聚合
buyer-portal Kotlin 买家 SSR 门户(Thymeleaf)
buyer-app Kotlin Multiplatform 买家 WASM 应用(frontend/kmp/buyer-app
seller-portal Kotlin Multiplatform 卖家门户静态发布单元(构建自 frontend/kmp/seller-app
profile-service Java 25 用户档案、地址簿
marketplace-service Java 25 商品目录、SKU、库存、评价
order-service Java 25 订单状态机、购物车(登录态)
wallet-service Java 25 钱包余额、充值/提现、Stripe 接入
promotion-service Java 25 促销引擎、优惠券(策略模式可扩展)
loyalty-service Java 25 积分账户、签到、积分兑换
activity-service Java 25 互动活动中心(插件化游戏引擎)
search-service Java 25 Meilisearch 全文搜索、Feature Toggle 试点
notification-service Java 25 邮件通知、Channel SPI 可扩展
webhook-service Java 25 Webhook 订阅、HMAC 签名、失败重试
subscription-service Java 25 订阅计划、自动续费

技术栈#

语言与框架基线#

维度 版本
JDK Java 25
Spring Boot 3.5.11
Spring Cloud 2025.0.1
Kotlin 2.3.20
构建工具 Maven + Maven Wrapper

父 POM 统一管理所有版本,通过 Maven Enforcer 强制最低 JDK 版本,各子模块继承父 POM 而不自行指定 Spring 版本。这让版本组合更容易复现和比较;至于是否直接作为生产基线,仍要结合团队支持策略与依赖兼容性评估。

基础设施#

维度 技术选择
数据库 MySQL 8.4(每服务独立 schema + Flyway 迁移)
消息队列 Apache Kafka 3.9(KRaft 模式,无需 ZooKeeper)
缓存 Redis 7.4 + Redisson(分布式锁、Lua 脚本)
搜索 Meilisearch 1.12
对象存储 Garage S3(兼容接口,存 Trace/Log 数据和商品图片)
支付 Stripe SDK(通过 Gateway 接口抽象,可插拔替换)

可观测栈#

flowchart TD App["应用层
Micrometer + OTLP Logback + shop.profiling"] OTel["采集层: OpenTelemetry Collector
Trace + Log + K8s 元数据富化"] Tempo["Tempo
Trace"] Loki["Loki
Log (OTLP)"] Grafana["展示层: Grafana"] Prometheus["指标: Prometheus
Exemplar (Trace ↔ Metric 双向关联)"] Pyroscope["持续分析: Pyroscope
CPU/内存火焰图"] Alert["告警: Prometheus Alert Rules
+ SLO Burn-rate Rules"] App -->|"OTLP"| OTel OTel --> Tempo OTel --> Loki Tempo --> Grafana Loki --> Grafana Prometheus --> Grafana App -->|"scrape"| Prometheus Prometheus --> Exemplar["Exemplar 关联 Trace"] Tempo -.->|"关联"| Pyroscope Loki -.->|"关联"| Pyroscope Prometheus --> Alert

所有 Java 服务通过 shop-commonObservabilityAutoConfiguration 自动装配,当前基线里就具备 metrics、traces、structured logs 和 profiling 接入点,不需要每个服务单独重复配置。


几个值得关注的设计决策#

Virtual Threads 替代 WebFlux#

Gateway 和所有 BFF/Domain 服务都启用了 Virtual Threads,而没有选 WebFlux。

原因:Virtual Threads 让 I/O 密集型微服务获得可接受的并发能力,同时保留了同步代码的可读性和可调试性。对于聚合多个下游调用的 BFF 来说,代码模型是:

// 并发读多个下游,代码仍然是同步风格
var profile = profileClient.getProfile(playerId);   // 实际运行在不同 VT 上
var cart = cartStore.getCart(sessionId);
var products = marketplaceClient.getProducts(productIds);

如果用 WebFlux,同样的逻辑会变成 Mono.zip(...) 链条,调试和错误追踪的成本都会上升。

Outbox Pattern 替代分布式事务#

跨服务传播的业务事实(如下单扣库存、充值通知积分)全部走:

sequenceDiagram participant Biz as 业务代码 participant DB as 数据库 participant Outbox as outbox 表 participant Pub as Publisher participant Kafka as Kafka participant Consumer as 消费端 Biz->>DB: 1. 写入业务数据 Biz->>Outbox: 2. 同事务写入 outbox 表 Note over Biz,Outbox: 同一本地事务,原子提交 Pub->>Outbox: 3. 定时轮询 PENDING 记录 Pub->>Kafka: 4. 发送到 Kafka 话题 Pub->>Outbox: 5. 标记 PUBLISHED Kafka->>Consumer: 6. 消费端幂等落地

好处:本地事务原子性有保证,事件可重放,失败可补偿,而且不依赖任何分布式事务协调器。

Strategy + Plugin 保持扩展性#

两个场景用了类似的思路:

促销引擎BenefitCalculatorConditionEvaluator 都是 SPI 接口,新增一种折扣规则只需实现接口,PromotionEngine 通过 Spring 自动发现。

活动游戏引擎GamePlugin 接口 + GamePluginRegistry,目前已有砸金蛋/抽奖、抢红包、集卡、虚拟养成四种插件。新增游戏类型至少不需要改引擎核心代码;是否需要重启或额外部署,仍取决于最终交付方式。每个插件有自己的扩展表前缀,Redis key 命名空间隔离。

shop-contracts 集中管理contract#

API path 常量、跨服务共享的 DTO、事件 envelope 全部放在 shop-contracts 模块。BFF、Portal、Worker 都从同一个地方引用,消除字符串拼接和 DTO 复制。

shop-common 的共享能力#

  • ApiResponse<T>:统一 northbound 响应模型
  • BusinessException + CommonErrorCode:统一错误语义(SC_ 前缀错误码)
  • HeaderPropagationInterceptor:在 RestClient 链路中继续透传 Gateway 注入的可信 Header
  • OTLP logback appender + 结构化日志自动配置

云原生工程实践#

Kubernetes 优先#

platform/k8s/ 目录包含完整的 K8s manifest:应用部署、基础设施(MySQL/Redis/Kafka)、可观测组件(Prometheus/Tempo/Loki/Grafana/Pyroscope)。本地用 Kind 集群运行,流程尽量贴近集群环境。

每个服务遵循统一端口规范(应用 8080,Actuator/Management 8081),K8s 探针、Prometheus ServiceMonitor、资源请求/限制在当前仓库里也都已经给出了对应配置。

Feature Toggle#

search-service 是试点场景:

OpenFeature SDK (供应商无关 API)
    → 仓库内 property provider
    → ConfigMap 目录挂载
    → Configuration Watcher + /actuator/refresh(热更新)

不依赖第三方控制面,用 K8s 原生能力就能完成动态配置下发。

ArchUnit 架构测试#

architecture-tests 模块通过 ArchUnit 验证代码约定:

  • Controller 不能直接调用 Repository
  • BFF 不能持有 JPA Entity,需要通过 HTTP 聚合领域服务
  • 不允许使用 RestTemplate 或手动创建传统线程池
  • Kafka 消费者需要实现幂等处理

架构约束变成可自动执行的测试用例,而不是靠 Code Review 口头约定。

Maven Archetype 脚手架#

shop-archetypes 提供 6 个模板:

Archetype 适用场景
gateway-service-archetype Spring Cloud Gateway 服务
auth-service-archetype OAuth2 资源服务器 + JWT
bff-service-archetype BFF 聚合层
domain-service-archetype JPA + Flyway + MySQL 领域服务
event-worker-archetype Kafka 消费者 + Outbox worker
portal-service-archetype Kotlin + Thymeleaf SSR 门户

新建服务时从 archetype 出发,开箱就有统一的目录结构、依赖、可观测配置和测试基类,不需要从旧模块复制再手工删改。


可能的参考方向#

这个项目的初衷是为真实项目的技术选型提供一个可运行的参照系。以下几个方向,我觉得更适合拿来做讨论起点:

技术版本组合:Java 25 + Spring Boot 3.5 + Spring Cloud 2025.0.1 是这套 POC 当前采用并跑通的一组组合。它对 2026 年的新项目可能有参考价值,但是否直接进入生产,还要结合团队对 JDK/Spring 支持周期、三方依赖兼容性和运维基线做判断。

Virtual Threads vs WebFlux:对于这个项目里的 I/O 密集型微服务,Virtual Threads 在这个项目里已经提供了可接受的并发能力,同时保留同步代码的工程优势。新项目如果没有明确的 Reactive/Streaming 诉求,可以先从 Virtual Threads 起步,再按压测结果决定要不要换模型。

可观测性的成本:把 OTLP + Prometheus + Tempo + Loki + Pyroscope 全部接进来,在这个项目里至少验证过一轮基础接线与排障路径。实际项目可以按需裁剪,但底层链路模型已经有了一个可对照样本。

事件驱动的落地姿势:Outbox Pattern 是一种在不引入分布式事务的前提下处理跨服务一致性的方案。本项目在 order、wallet、marketplace、activity 等服务里都有具体实现,适合拿来讨论边界和取舍。

SPI 驱动扩展性:促销引擎和活动游戏引擎的 Strategy/Plugin 设计,在业务规则经常变化的场景下能降低主线代码的膨胀速度。它不一定适合所有团队,但至少提供了一个比较清晰的扩展样例。


参考与实现位置#


下一篇#

下一篇会深入 API Gateway 模块:Spring Cloud Gateway Server MVC 的路由配置、JWT 校验过滤器、Redis Lua 限流、Trusted Headers 注入,以及从 WebFlux 迁移到 MVC + Virtual Threads 的背景和得失。

项目仓库:github.com/meirongdev/shop(公开,可结合源码一起看)