DDD(Domain-Driven Design 领域驱动设计)是由Eric Evans最先提出,目的是对软件所涉及到的领域进行建模,以应对系统规模过大时引起的软件复杂性的问题。
服务架构调用关系
应用层 Application
1)应用服务位于应用层,用来表述应用和用户行为,负责服务的组合、编排和转发,负责处理业务用例的执行顺序以及结果的封装
2)应用层的服务包括应用服务和领域事件相关服务
3)应用服务可对微服务内的领域服务以及微服务外的应用服务进行组合和编排,或者对基础层如文件、缓存等数据直接操作形成应用服务,对外提供粗粒度的服务
4)领域事件包括两类:领域事件的发布和订阅,通过事件总线和消息队列实现异步数据传输,实现微服务之间的解耦
领域层 Domain
1)领域服务位于领域层,未完成领域中跨实体或值对象的操作转换而封装的服务,领域服务以与实体/值对象相同的方式参与实施过程
2)领域服务对同一个实体的一个或多个方法进行组合和封装,或对多个不同的实体的操作进行组合或编排,对外暴露成领域服务。领域服务封装了核心的业务逻辑。实体自身的行为在实体内部实现,向上封装成领域服务暴露
3)为隐藏领域层的业务逻辑实现,所有领域方法和服务等须通过领域服务对外暴露
4)为实现微服务内聚合之间的解耦,原则上禁止跨聚合的领域服务调用和跨聚合的数据相互关联
基础层 Infrastructure
1)基础服务位于基础层,为各层提供资源服务(比如数据库、缓存等),实现各层的解耦,降低外部资源变化对业务逻辑的影响
2)基础服务主要为仓储服务,通过依赖倒置的方式为各层提供基础资源服务,领域服务和应用服务调用仓储服务接口,利用仓储实现持久化数据对象或直接访问基础资源
接口层 Interfaces
1)接口层位于用于接口层,用于处理用户发送的请求和解析用户的输入的配置文件等,并将信息传递给应用层
除此之外,DDD结构它是一种充血模型结构,所有的服务实现都以领域为核心,应用层定义接口,领域层实现接口,领域层定义数据仓储,基础层实现数据仓储中关于DAO和Redis的操作,但同时上述模块之间又有互相的依赖。这样的结构再开发独立领域提供 http 接口时候,并不会体现出什么问题。但如果这个时候需要引入 RPC 框架,就会暴露问题了,因为使用 RPC 框架的时候,需要对外提供描述接口信息的 Jar 让外部调用方引入,才可以通过反射的方式调用到具体的方法提供者,那么这个时候,RPC 需要暴露出来,而 DDD 的系统结构耦合度又较高,怎么进行模块化的分离就成了问题点。
因此,如果按照模块化拆分,需要进行一些处理:
- 应用层:不再给领域层定义接口,而是自行处理对领域层接口的包装,否则领域层既引入了应用层的Jar,应用层也引入了领域层的Jar,就会出现循环依赖的问题
- 基础层:数据仓储的定义的需要从领域层剥离,否则也会出现循环依赖的问题
- RPC层:定义接口描述,包括入参Req、出参Resp、DTO、接口信息,这些内容定义出来的Jar提供给接口层,也提供给外部调用方