把工程约束写进结构的微服务骨架

Java 21 · Spring Boot 4 · Spring Cloud 2025 · Spring AI 2.0

一篇基于真实源码的技术全景 · DDD 四层 + CQRS · 27 个即插即用 Starter

搭过微服务的人,大概率都栽过同样几个坑。

公共包越滚越大,改一行牵一发动全身;能力无法复用,每个新服务都重配一遍;说好的分层,写着写着 Controller 里就开始写 SQL;配置散落各处,换个数据库地址要翻好几个文件。MateCloud 想给的,是另一种答案。

01

一句话理念,五层架构

MateCloud 的设计理念可以浓缩成一句话——极简公共层、各司其职、Starter = 即插即用能力。它不追求“大而全”把你用不上的东西塞满,也不甘于“散而乱”让每个新服务重踩一遍坑。

技术底座足够新:Java 21、Spring Boot 4.0.7、Spring Cloud 2025.1.2、Dubbo 3.3.6、Spring AI 2.0。开源版含 网关 / 认证 / 系统管理 / 通知 四个核心服务,外加 27 个 Starter,并支持单体与微服务双形态一键切换。整体是清晰的五层结构。

图片

关键设计是:mate-common 是纯类型、零自动装配——它只提供 BaseEntity、Result、雪花 ID 这类基础类型,绝不夹带任何 Spring 配置。所有“能力”都下沉到 Starter,谁需要谁引入。

02

DDD 四层:把架构约束写进代码结构

MateCloud 不只是“能跑的微服务”,它是一套 DDD 落地范本。每个业务模块严格遵循四层结构,包名即架构:依赖方向一律指向领域层,领域层不知道 Spring、MyBatis、数据库的存在。

图片

这套结构背后有五条铁律:

  • 领域层零框架依赖

    ——不允许出现 Spring / MyBatis 注解,纯业务逻辑;

  • 仓储接口在 domain,实现在 infrastructure

    ——依赖倒置;

  • 聚合根强制不变量

    ——状态变更只能走聚合方法;

  • CQRS 读写分离

    ——CommandService 与 QueryService 泾渭分明;

  • MapStruct 全量转换

    ——绝不手写 get/set 拷贝字段。

“聚合根强制不变量”不是口号。以用户实体为例,冻结 / 已删账号禁止自助改密,这条业务规则被守卫在实体方法里,任何路径都绕不过去:

mate-system · domain/model/entity/User.java

public void changePassword(String encodedPassword) {     checkActive();          // 冻结/删除账号禁止自助改密this.password = encodedPassword; }private void checkActive() {    if (isFrozen())        throw UserException.of(USER_IS_FROZEN);    if (isDomainDeleted()) throw UserException.of(USER_IS_DELETED); }

好处显而易见:新人接手,看包名就懂分层;重构业务,改动被牢牢限制在该在的层里;业务规则写在聚合里,谁都无法绕过。

03

27 个 Starter:能力像积木一样拼装

MateCloud 把每一项能力都封装成独立 Starter,引入即生效,不引入零负担。核心 7 个几乎必用,业务和进阶按需添加。

分类

代表能力

核心 7

web · ds(MyBatis+Druid+Flyway) · cache(双级缓存+分布式锁+雪花ID) · nacos · rpc(Dubbo) · sa-token · monitor

业务

mq(领域事件) · job(XXL-Job) · security(限流/审计/幂等/数据权限/验签) · file(MinIO) · excel · tenant(多租户)

高级 contrib

ai · gray(灰度) · seata(分布式事务) · sentinel(熔断限流) · sharding(分库分表) · flow · rule · test

背后是 Spring Boot 3+ 的自动装配机制:Starter 在 AutoConfiguration.imports 里声明配置类,配置类用条件注解按依赖存在性决定装哪些切面——引入即生效、缺依赖则静默降级

mate-security-starter · SecurityAutoConfiguration.java

@Bean@ConditionalOnBean(RedissonClient.class)   // 有 Redisson 才装限流切面public RateLimitAspect rateLimitAspect(RedissonClient redisson) {    return new RateLimitAspect(redisson); }

于是一个典型业务服务的依赖,往往就是“核心 7 + 三两个业务 Starter”,application.yml 只有十来行——能力靠拼装,不靠复制粘贴

04

一个 @Tool 注解,业务方法变 AI 工具

很多团队给系统接 AI,最后都停在了“一个会聊天的机器人”:它能答通用问题,却碰不到你的业务数据。MateCloud 的 mate-ai-starter(基于 Spring AI 2.0)把这层胶水全包了——给任意 Spring Bean 的方法加一个 @Tool 注解,它就自动成为 AI 可调用的工具

mate-system · trigger/ai/DictAiTools.java

@Tool(description = "List all dict entries for a given dictType.")public List<DictData> listDictByType(        @ToolParam(description = "Dict type code, e.g. 'user_status'")         String dictType) {    return dictQueryService.findByType(dictType); }

没有手写 JSON Schema,没有工具注册表,没有胶水代码。背后是一个 BeanPostProcessor:容器启动时扫描每个 Bean 的方法,凡带 @Tool 的就构建成 MethodToolCallback 注册进中央注册表。而这个注册表本身就是 ToolCallbackProvider,可以直接喂给 ChatClient。

图片

最妙的是——同一批工具会同时暴露给四个入口:REST、SSE 流式对话、CLI(mate ai chat)、以及 MCP(mate --mcp)。写一次业务方法,AI 从任何入口都能调用。模型侧支持 6 家 LLM:Anthropic、OpenAI、智谱、Minimax、DeepSeek、Ollama。

05

网关 HMAC 签名:堵住身份头伪造

微服务里有个经典的越权漏洞:网关鉴权后,把用户身份以明文头 X-User-Id 透传给下游。可一旦攻击者绕过网关、直连服务端口,随手发一个 X-User-Id: 1 就能冒充超管。

图片

MateCloud 的解法:网关持有一把共享密钥,对整套身份头 + 时间戳做 HMAC-SHA256 签名;下游用同一把密钥重算比对。攻击者没有密钥,就无法为任何伪造的身份头组合算出合法签名。

mate-base · GatewaySignature.java(纯 JDK,网关与下游共用一份)

// 规范化载荷:每个身份头值换行拼接,再接时间戳for (String header : AuthHeaders.ALL)     sb.append(lookup.apply(header)).append('\n');return hmac(secret, sb.append(ts).toString());  // HmacSHA256

整套身份头签名(而不只是 user id),意味着篡改任意一个头都会让签名失效;时间戳则限定了重放窗口。网关若没配置密钥,直接 fail-fast 拒绝启动——安全默认是“打开”的。

06

单体 / 微服务:一个属性切换

微服务的运维成本,早期团队未必扛得住。MateCloud 让同一套业务模块,既能拆成微服务(Dubbo + Nacos),又能打成单体 JAR 进程内直调。切换靠一个属性,而非改代码。

图片

秘密在于依赖倒置留下的“接缝”:跨服务调用都走一个端口接口(如 UserQueryPort),由条件注解决定注入哪个适配器:

mate-monolith · LocalUserQueryAdapter.java

@Component@ConditionalOnProperty(name = "mate.rpc.mode", havingValue = "local")public class LocalUserQueryAdapter implements UserQueryPort {    // 单体:进程内直调 mate-system 的 query service// 微服务:换成 DubboUserQueryAdapter 走 Dubbo,接口不变}

本地开发用单体、单进程起得快;生产部署拆微服务、按需扩缩。业务代码一行不用改。

07

技术栈全景与三分钟启动

以下版本均取自项目根 pom.xml 的真实依赖声明:

核心框架

Java 21 · Spring Boot 4.0.7 · Spring Cloud 2025.1.2 · Spring AI 2.0

微服务生态

Nacos 3.2 · Dubbo 3.3.6 · Sa-Token 1.45 · Spring Cloud Gateway · Sentinel / Seata

数据与缓存

MySQL 8.3 · MyBatis-Plus 3.5.16 · Druid · Flyway · Redisson 4.5 · Caffeine + Redis 双级缓存

中间件 / 存储

RabbitMQ(领域事件+延迟队列) · XXL-Job · MinIO 8.5 / AWS S3

工具库

MapStruct 1.6 · Lombok · Hutool · fastjson2 · EasyExcel · Smart-Doc(非 Swagger)

跑起来只要四步:

# 1. 编译mvn clean install -DskipTests# 2. 启动基础设施:MySQL + Redis + RabbitMQ + Nacos + MinIOmake infra-up# 3. 初始化 Nacos 配置java -jar mate-cli/target/mate-cli.jar config init# 4. 启动全部服务(Flyway 首启自动建表 + 内置 admin/admin123)make up

数据库无需手动建表——mate-system 首启时 Flyway 自动执行迁移,完成建表、内置账号、角色、菜单与字典的初始化。

08

写在最后:好架构是“约束”出来的

MateCloud 的价值,不在于堆了多少组件,而在于用清晰的分层、即插即用的能力包、严格的 DDD 约束、AI 原生的工具编排、内建的安全加固,把“好的工程实践”固化进了项目结构本身。

想加能力?引一个 Starter。
想接 AI?给方法加个 @Tool。
想从微服务变单体?改一个属性。

它不是“能跑的 Demo”,而是一套把工程约束前置到脚手架里的开源底座。全部代码 Apache-2.0 协议开放,欢迎 star、fork、提 PR。

TO BE CONTINUED

🦞 但这,只是一副骨架

还记得第 04 节那个 @Tool 吗?如果说 MateCloud 是一副长好了的骨架,那接下来的两件事,是让它“长出手脚”、再“学会繁殖”。

🦞 MateClaw · 一个你 IT 部门敢签字的 AI Agent 平台

Spring Boot inside,一个 JAR 就能交付。它不做“聊天机器人”,做的是有角色、有目标、能审批的数字员工(ReAct + Plan-and-Execute):14+ 模型多厂商容灾自动切换、带来源引用的 LLM Wiki 知识库、RBAC + 审批门 + 全链路审计、Web / 桌面 / 嵌入组件 / 8 个 IM 多端接入。self-hosted,$0,数据和密钥都在你自己手里。

而它和 MateCloud 的接缝,正是那个 @Tool——把 mate-cli 与业务工具接成 MCP,数字员工就能直接操作你的微服务集群:查服务、调 RPC、生成模块、迁移数据库。不是 AI 帮你写代码,是 AI 直接开你的系统。

🧬 从“骨架”到“平台 + 应用”生态

MateCloud 的下一步,是从一套单体骨架,进化成一个 Platform:CRM、商城、短视频、教学、OA…… 一个个子系统长在同一副底座上,通过 mate-api 的 RPC、领域事件、网关统一路由共享同一个平台。而生成一个新子系统,只需要——你大概已经猜到了——一条 mate-cli 命令

当一副骨架学会了自己生长,
微服务开发,会变成什么样子?

—— 下一篇,我们聊聊 MateClaw 与 MateCloud 的产品生态。

官网

mate.vip

MateCloud(开源骨架)

github.com/matevip/matecloud

MateClaw(AI Agent 平台)

github.com/mateaix/mateclaw

技术栈 · 协议

Java 21 · Spring Boot 4 · Spring Cloud 2025 · Spring AI 2.0 · Apache-2.0

更多推荐