领域驱动与微服务落地实战-工程结构

领域驱动与微服务落地实战-工程结构

传统项目工程结构

目前maven/gradle已经成为j2ee应用开发的事实标准,以maven项目为例,常规的微服务工程结构如下

api

  • dto 数据传输模型
  • facade(即soa interface)

service

  • serviceImpl 无状态 主要的业务代码实现,是事物的核心过程,
  • bo 对象 业务模型
  • transfer 对象 dto(包括自身接口和下游接口)->bo bo->po

infra

  • repo (mybatis|hibernate)
  • po 持久化模型
  • soa client 下游接口

maven分多module的目的主要是做代码依赖隔离,和软件打包控制。按上图所示,api依赖service,
service依赖infra,这个是最简单的一个方案,实际项目中还有以下几种变种。

api 基于cqrs原则拆分成读写两套api,不拆maven module,一般通过类或者包拆分
service 可以基于垂直业务领域拆包,或者拆module(不建议,如果需要到拆module的程度,建议拆服务)

基于水平业务拆分一层biz module 出来,解决service本身臃肿和复用问题。
把service拆成可复用的单事物业务,和不可复用的大型业务两种。单事物业务之间不可互相引用。

也可以单独把main函数拆成一个独立module,方便集成测试和单元测试,常见于spring boot项目

infra 把数据库访问单独拆 module,避免研发人员使用其他中间件api
基于代码稳定性考虑,把soa client单独拆一个module,最大限度的隔离下游服务对核心业务代码的影响。

基于领域驱动设计工程结构

api 与传统项目的api模块没有区别

service 与传统项目的service模块相比,都是无状态的,也是事物的核心过程,但不是业务逻辑的核心实现,
业务逻辑包装在domain内,service主要是协调一个或者多个domain对象,并且不能访问infra

infra 与传统项目的infra模块相比,依赖domain,代表是domain领域对象依赖组件的具体实现

domain 领域驱动架构的核心业务代码层,代码稳定,不依赖其他任何module,无外部依赖(基本只依赖java sdk)
便于单元测试 和代码迁移

application main函数所在模块,主要是方便集成测试,和service模块的单元测试,并且mq的消费者也建议在该模块

其他

  • maven的代码隔离,其实是编译阶段的隔离,通常在运行期业务代码都是appClassLoader加载,
    不同maven module之间的代码在运行期其实是不隔离,所以要禁止通过反射等其他手段绕过相关访问限制
  • 在maven出现之前,传统的java应用都是ant打包方案,通过java的访问控制修饰符来控制代码访问权限,
    但事实上,java代码访问控制修饰符大部分常见下基本只用private public,很少会基于包做严格的访问隔离,
    最终maven多模块成为事实上的隔离标准。