平台架构全景:六边形架构与多域单体整合
一篇关于六边形架构的立论文:把「跨域只走 api 门面」从口头约定写成编译期不可逾越的结构——单体聚合与微服务双形态业务代码零改动。
附件
- fig-platform-panorama.png(253 KB)下载
平台架构全景:六边形架构与多域单体整合
「问渠那得清如许?为有源头活水来。」系统的清爽从不在各域自扫门前雪,而在「源」与「廊」的结构:源头只进不改,走廊只此一条。本篇叙述全平台架构——五层六边形、跨域唯一门面、单体聚合与微服务双形态。
一、界定:六边形不是目录仪式
先划清边界:五层架构讨论的是依赖方向与对话路径,不是「哪个文件放哪个目录」。层是责任的下界:api 是唯一对外走廊,domain 是纯领域,application 只做编排,infrastructure 承载技术,bootstrap 负责启动。违反层界不是「不规范」,而是「把地板抄进屋顶」。
| 层 | 职责 | 关键约定 |
|---|---|---|
| api | 对外 Dubbo 契约门面 + command/result POJO | 方法返回 result,POJO 实现 Serializable;实现类用 @DubboService 注册 |
| domain | 纯领域模型、仓储接口、领域端口 | 不引入任何框架依赖 |
| application | 用例编排、事务、功能权限校验统一入口、跨域端口 | ApplicationQuery / ApplicationPort 抽象;不直接依赖基础设施 |
| infrastructure | REST 控制器、MyBatis-Plus 仓储、Redis、Liquibase schema、OpenAPI 分组 | 只扫本域包;只声明本域特有依赖 |
| bootstrap | 微服务启动编排 | 每域独立端口段 |
二、为什么必须:靠约定终将崩塌
没有这套结构的平台完全可以「靠约定」生长:新域随意 import 别人的应用类、共享全局配置,直到单体聚合那天处处冲突——SpringDoc 全局 Bean 被覆盖、Dubbo starter 冲突、跨域装配连环失败,每一条拆开看都没问题,合到一起全部爆掉。约定的脆弱在于:它依赖记忆与自觉,而记忆与自觉会随人员流失而蒸发。结构的好处因此是第一性的:把「跨域只走 api 门面」从口头约定,写成编译期不可逾越的结构。
三、机理:走廊、聚合与双形态
每个域五层闭环之后,平台只剩两件事:横向共享与纵向聚合。
- 横向共享:domains/common/domain 放三层异常与分页等纯抽象;domains/common/infrastructure 收拢共享依赖(web / mybatis-plus / liquibase / dubbo 随本模块透传);commons/* 提供语言级能力——业务域只见能力不见框架;
- 纵向聚合:根 bootstrap 单体(monolith profile,端口 9005)逐域追加 infrastructure 依赖,master changelog 按域 include 各不冲突,@EnableDubbo 扫描所有门面实现,SpringDoc 各域分组自动合并并由 MonolithDocsRouteController 提供 /drizzlepal/apidoc/<分组>/swagger 直达路由;
- 双形态:单体只是聚合形态,微服务 profile 切换为各域独立 bootstrap 与 Dubbo Reference——业务域代码一行不改。
Monorepo 三仓库(backend / frontend / infrastructure)经子树脚本同步,「写后即推」是动作而不是项目。
四、思辨:分层是有税的
要诚实说出「过犹不及」:为每个简单用例付出的样板代码,是分层征收的利息。六边形是付得起这笔税的复杂业务的门票,不是 hello world 的圣旨。检验的良知尺是「去一验证」:去掉 infrastructure 分层,简单业务照样活;去掉 domain 与 application 的边界,判定逻辑与用例编排绞死在一起——前一种可省,后一种不能省。结构服务于业务,而不是反客为主。
五、回到现实:新域五步
新域接入从五步开始:模块接入(domains/pom.xml 与聚合 bootstrap/pom.xml 按依赖顺序)、changelog include、双向端口打通、鉴权收口、日志对齐——细节清单见风控域一文。分层的价值最终只在一处兑现:新东西来的时候,有地方放。