微服务项目拆模块时,最容易走两个极端:一是所有东西都塞进公共模块,二是每个服务重复复制一份代码。这个项目最终采用的边界是:公共模块只放稳定契约和横切能力,不替业务服务决定运行时技术栈。
一、模块划分
service-common 公共契约和横切能力
service-provider 业务数据和核心接口
service-consumer Feign 消费方
service-gateway 唯一流量入口
service-mail 邮件领域服务
MP-Generator 独立代码生成工具
MP-Generator 没放进父 POM 聚合,因为它是开发工具,不是线上服务。业务构建不应该因为一个代码生成器而增加数据库驱动等额外依赖。
二、service-common 里放什么
当前公共模块包含:
ApiResponse统一响应- 全局异常处理
- Web 接口日志切面
- DTO
- 共享 Feign 契约
- API 路径自动配置
这些都属于多个服务共同遵守的契约,或者和具体业务无关的横切能力。
三、公共模块不能背太多运行时依赖
一个典型错误是把 Web、Swagger、数据库、Sentinel 全塞进 common。这样所有依赖它的服务都会被迫继承这些依赖。
这个项目后来重构成:
| 能力 | 声明位置 |
|---|---|
| Web 容器 | provider、consumer、mail |
| OpenFeign starter | consumer |
| Swagger UI | 各文档服务或 gateway |
| 数据库和邮件 | 对应业务模块 |
| WebFlux | gateway |
公共模块只保留源码直接使用的编译 API,例如 Spring Web 注解、Feign Core、Validation、SpringDoc common。
四、Gateway 不依赖 common
service-gateway 是 WebFlux 应用,service-common 里的 @RestControllerAdvice 和 WebMVC 切面不能直接复用。如果为了一个统一响应结构把
WebMVC 依赖带进 Gateway,很容易出现 Web 栈冲突。
所以 Gateway 独立实现:
- WebFlux 错误处理器
- 全局请求日志过滤器
- Sentinel Gateway 适配
- 自己的统一 JSON 响应 record
五、自动装配边界
公共组件通过 Spring Boot 自动装配文件注册:
META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
业务服务引入 service-common 后,不需要手动 @Import。但自动装配也应该克制,只注册真正全局生效的组件。