模块化强封装要求DTO严格限定在独立的commons-dto模块中,仅含POJO与校验注解,其他模块compile-only引入;跨服务调用必须使用该模块定义的契约DTO,禁止复用实体或内部对象,字段重复需手动声明,继承被禁用,CI强制校验边界合规性。

模块化强封装不是给DTO加个private修饰符,而是通过工程边界把DTO的定义、使用和演化彻底锁在契约层里。关键在于让DTO成为模块间唯一合法的数据“通关文牒”,而不是到处流转的共享对象。
用独立模块承载DTO契约
把所有DTO类(Request/Response/VO)统一放在一个名为commons-dto的Maven模块中,该模块不依赖任何业务模块,也不含任何逻辑代码,只包含POJO和JSR-380校验注解。其他服务模块仅以compile-only方式引入它——编译时可见,运行时不打包进去,避免隐式耦合。
- 订单服务引用commons-dto,但不能访问用户服务的Entity或DAO
- 前端SDK直接基于commons-dto生成,与后端实现完全解耦
- DTO字段变更必须走语义化版本升级(如1.2.0 → 1.3.0),触发所有消费者CI自动检查兼容性
禁止跨模块直接复用内部对象
不允许A服务把B服务的UserEntity、OrderBO甚至B服务自用的内部DTO当作参数或返回值。所有跨服务调用必须经由commons-dto中明确定义的接口契约对象,例如:
- 订单服务调用用户服务时,入参是
UserQueryRequest,出参是UserProfileVO - 哪怕两个服务都用“id”“name”,也不能共用同一个UserDTO类——各自在commons-dto中定义语义等价但物理隔离的DTO
- 数据库实体(PO/Entity)绝对不出现在DTO模块,也不允许被Feign客户端或OpenFeign解码器直接反序列化
用接口+DTO组合替代对象继承
避免为“复用字段”而让DTO之间继承(如BaseRequestDTO → CreateOrderRequestDTO)。继承会破坏模块边界,导致修改父类影响所有下游。正确做法是:
- 每个DTO独立定义,重复字段手动声明(IDE可自动同步)
- 共性行为抽成工具接口,例如
Validatable、Traceable,由DTO实现而非继承 - 用MapStruct等转换器显式声明字段映射关系,让转换逻辑可读、可测、可审计
构建期强制隔离校验
在CI流水线中加入静态分析规则,拦截任何违反封装的行为:
- 扫描业务模块代码,禁止import路径含
entity、repository、domain的类 - 检查Feign Client接口的参数/返回类型,必须属于commons-dto包下
- 验证Controller层方法签名:@RequestBody只能是XxxRequest,@ResponseBody只能是XxxResponse或XxxVO

















