领域驱动与微服务落地实战-工程结构
领域驱动与微服务落地实战-工程结构
传统项目工程结构
目前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多模块成为事实上的隔离标准。