14、如何⽤DDD设计微服务代码模型

news2024/11/23 1:37:53

        在完成领域模型设计后,接下来我们就可以开始微服务的设计和 落地了。在微服务落地前,⾸先要确定微服务的代码结构,也就是我 下⾯要讲的微服务代码模型。

        只有建⽴了标准的微服务代码模型和代码规范后,我们才可以将 领域对象映射到代码对象,并将它们放⼊合适的代码⽬录结构中。标 准的代码模型可以让项⽬团队成员更好地理解代码,根据统⼀的代码 规范实现团队协作,也可以让微服务各层的业务逻辑互不⼲扰、分⼯ 协作、各据其位、各司其职,避免不必要的代码混淆,还可以让你在 微服务架构演进时,轻松完成代码重构。

DDD分层架构与微服务代码模型

        我们参考DDD分层架构模型来设计微服务代码模型。没错!微服 务代码模型就是依据DDD分层架构模型设计出来的。

        我们先简单回顾⼀下DDD分层架构模型,如图14-1所⽰。它包括 ⽤户接⼝层、应⽤层、领域层和基础层,分层架构各层的职责边界⾮ 常清晰,能有条不紊地分层协作。

  • ⽤户接⼝层:⾯向前端⽤户提供服务和数据适配。这⼀层聚集了 接⼝和数据适配相关的功能。
  • 应⽤层:实现服务组合和编排,主要适应业务流程快速变化的需 求。这⼀层聚集了应⽤服务和事件订阅相关的功能。
  • 领域层:实现领域模型的核⼼业务逻辑。这⼀层聚集了领域模型 的聚合、聚合根、实体、值对象、领域服务和事件等领域对象,通过 各领域对象的协同和组合形成领域模型的核⼼业务能⼒。
  • 基础层:它贯穿所有层,为各层提供基础资源服务。这⼀层聚集 了各种底层资源相关的服务和能⼒。

        领域模型的业务逻辑从领域层、应⽤层到⽤户接⼝层逐层组合和 封装,对外提供灵活的服务。既实现了各层的分⼯和解耦,⼜实现了 各层的协作。因此,⽏庸置疑,DDD分层架构模型是微服务代码模型 最合适的选择。

微服务代码模型

        其实,DDD并没有给出标准的代码模型,不同的⼈可能会有不同 理解,也会结合⾃⼰项⽬的情况进⾏个性化设计。下⾯要说的这个微 服务代码模型是我经过思考和实践后建⽴起来的,主要考虑了微服务 边界、聚合边界、分层、解耦和微服务的架构演进等因素.

⼀级代码⽬录

        微服务⼀级⽬录是按照DDD分层架构的分层职责来定义的。 在微服务代码模型⾥,我们分别定义了⽤户接⼝层、应⽤层、领 域层和基础层四层,并分别为它们建⽴了interfaces、application、 domain和infrastructure四个⼀级代码⽬录。

这些代码⽬录的职能和代码形态如下。

  • interfaces(⽤户接⼝层):它主要存放⽤户接⼝层与前端应⽤交 互、数据转换和交互相关的代码。前端应⽤通过这⼀层的接⼝,从应 ⽤服务获取前端展现所需的数据。处理前端⽤户发送的REStful请求, 解析⽤户输⼊的配置⽂件,并将数据传递给application层。数据的组 装、数据传输格式转换以及facade接⼝封装等代码都会放在这⼀层⽬ 录⾥。
  • application(应⽤层):它主要存放与应⽤层服务组合和编排相 关的代码。应⽤服务向下基于微服务内的领域服务或外部微服务的应 ⽤服务,完成服务的组合和编排,向上为⽤户接⼝层提供各种应⽤数 据⽀持服务。应⽤服务和事件等代码会放在这⼀层⽬录⾥。
  • domain(领域层):它主要存放与领域层核⼼业务逻辑相关的代 码。领域层可以包含多个聚合代码包,它们共同实现领域模型的核⼼ 业务逻辑。聚合内的聚合根以及实体、⽅法、值对象、领域服务和事 件等相关代码会放在这⼀层⽬录⾥。
  • infrastructure(基础层):它主要存放与基础资源服务相关的代 码。为其他各层提供的通⽤技术能⼒、三⽅软件包、数据库服务、配 置和基础资源服务的代码都会放在这⼀层⽬录⾥。

各层代码⽬录

下⾯我们⼀起来看⼀下⽤户接⼝层、应⽤层、领域层以及基础层 各⾃的⼆级代码⽬录结构。

1. ⽤户接⼝层

interfaces⽬录下的代码⽬录结构有assembler、dto和facade三类。

  •  assembler:实现DTO与DO领域对象之间的相互转换和数据交 换。⼀般来说,assembler与dto总是同时出现。
  • dto:它是前端应⽤数据传输的载体,不实现任何业务逻辑。我 们可以⾯向前端应⽤将应⽤层或领域层的DO对象转换为前端需要的 DTO对象,从⽽隐藏领域模型内部领域对象DO;也可以将前端传⼊的 DTO对象转换为应⽤服务或领域服务所需要的DO对象。
  • facade:封装应⽤服务,提供较粗粒度的调⽤接⼝,或者将⽤户 请求委派给⼀个或多个应⽤服务进⾏处理。

2.应⽤层

application的代码⽬录结构有event和service,如图

  • event(事件):这层⽬录主要存放事件相关的代码。它包括两个 ⼦⽬录:publish和subscribe。前者主要存放事件发布相关代码,后者 主要存放事件订阅相关代码。事件处理相关的核⼼业务逻辑在领域层 实现。
  • 应⽤层和领域层都可以进⾏事件发布。为了实现事件订阅的统⼀ 管理,建议你将微服务内所有事件订阅的相关代码都统⼀放到应⽤ 层。事件处理相关的核⼼业务逻辑实现可以放在领域层。通过应⽤层 调⽤领域层服务,来实现完整的事件订阅处理流程。
  • service(应⽤服务):这层的服务是应⽤服务。应⽤服务会对多 个领域服务或其他微服务的应⽤服务进⾏封装、编排和组合,对外提 供粗粒度的服务。你可以为每个聚合的应⽤服务设计⼀个应⽤服务 类。
  • 另外,在进⾏跨微服务调⽤时,部分DO对象需要转换成DTO,所 以应⽤层可能也会有⽤户接⼝层的assembler和dto对象。这时,你可以 根据需要增加assembler和dto代码⽬录结构。

注意: 对于多表关联的复杂查询,由于这种复杂查询不需要有领域逻辑和业 务规则约束,因此不建议将这类复杂查询放在领域层的领域模型中。 你可以通过应⽤层的应⽤服务采⽤传统多表关联的SQL查询⽅式,也 可以采⽤CQRS读写分离的⽅式完成数据查询操作。 

3. 领域层 

        domain下的⽬录结构是由⼀个或多个独⽴的聚合⽬录构成,每⼀ 个聚合是⼀个独⽴的业务功能单元,多个聚合共同实现领域模型的核 ⼼业务逻辑。

        聚合内的代码模型是标准且统⼀的,它⼀般包括entity、event、 repository和service四个⼦⽬录。

         aggregate(聚合):它是聚合⽬录的根⽬录,你可以根据实际项 ⽬的聚合名称来命名,⽐如将聚合命名为“Person”。

        聚合内实现⾼内聚的核⼼领域逻辑,聚合可以独⽴拆分为微服 务,也可以根据领域模型的演变,在不同的微服务之间进⾏聚合代码 重组。 将聚合所有的代码放在⼀个⽬录⾥的主要⽬的,不仅是为了业务 的⾼内聚,也是为了未来微服务之间聚合代码重组的便利性。有了清 晰的聚合代码边界,你就可以轻松地实现以聚合为单位的微服务拆分 和重组。 聚合之间的松耦合设计和清晰的代码边界,在微服务架构演进中 具有⾮常重要的价值。 聚合内可以定义聚合根、实体和值对象以及领域服务等领域对 象,⼀般包括以下⽬录结构。

  • entity(实体):它存放聚合根、实体和值对象等相关代码。实 体类中除了业务属性,还有业务⾏为,也就是实体类中的⽅法。如果 聚合内部实体或值对象⽐较多,你还可以再增加⼀级⼦⽬录加以区 分。
  • event(事件):它存放事件实体以及与事件活动相关的业务逻辑 代码。
  • service(领域服务):它存放领域服务、⼯⼚服务等相关代码。 ⼀个领域服务是由多个实体组合出来的⼀段业务逻辑。你可以将聚合 内所有领域服务都放在⼀个领域服务类中。如果有些领域服务的业务 逻辑相对复杂,你也可以将⼀个领域服务设计为⼀个领域服务类,避 免将所有领域服务代码都放在⼀个领域服务类中⽽出现代码臃肿的问 题。领域服务可以封装多个实体或⽅法供上层应⽤服务调⽤。
  • repository(仓储):它存放仓储服务相关的代码。仓储模式通常 包括仓储接⼝和仓储实现服务。它们⼀起完成聚合内DO领域对象的持 久化,或基于聚合根ID查询,完成聚合内实体和值对象等DO领域对象 的数据初始化。另外,仓储⽬录还会有持久化对象PO,以及持久化实 现逻辑相关代码,如DAO等。在仓储设计时有⼀个重要原则,就是⼀ 个聚合只能有⼀个仓储。

注意 按照DDD分层架构,仓储本应该属于基础层。但为了在微服务架构 演进时保证聚合代码重组的便利,这⾥将仓储相关代码也放到了领域 层的聚合⽬录中。 这是因为聚合和仓储总是⼀对⼀的关系,将领域模型和仓储的代码组 合在⼀起后,就是⼀个包含了领域层领域逻辑和基础层数据处理逻辑 的聚合代码单元。⼀旦领域模型发⽣变化,当聚合需要在不同的限界 上下⽂或微服务之间进⾏代码重组时,我们就可以以聚合代码包为单 元,进⾏整体拆分或者迁移,轻松实现微服务架构演进。虽然领域相关的业务逻辑代码和基础资源处理相关的代码都在⼀个聚 合代码⽬录下,但是聚合的核⼼业务逻辑仍然是通过调⽤仓储接⼝来 访问基础资源的仓储实现处理逻辑,所以这样不会影响业务逻辑与基 础资源逻辑的依赖倒置设计。

 4. 基础层

infrastructure的代码⽬录结构有config和util两个⼦⽬录

  • config:主要存放配置相关代码
  • util:主要存放平台、开发框架、消息、数据库、缓存、⽂件、 总线、⽹关、第三⽅类库和通⽤算法等基础代码。你可以为不同的资源类别建⽴不同的⼦⽬录

本章⼩结

        我们根据DDD分层架构模型,建⽴了微服务的标准代码模型。在 代码模型⾥⾯,各层的代码对象各据其位、各司其职,共同协作完成 微服务的业务逻辑。 关于微服务代码模型我还需要强调两点内容。 第⼀点,聚合之间的代码边界⼀定要清晰。

        聚合之间的服务调⽤ 和数据关联应该尽可能松耦合和低关联,聚合之间的服务调⽤应该通 过上层的应⽤层组合实现调⽤,原则上不允许聚合之间直接调⽤领域 服务。这种松耦合的聚合代码关联,在以后业务发展和需求变更时, 可以很⽅便地实现业务功能和聚合代码的重组,在微服务架构演进中 将会起到⾮常重要的作⽤。

         第⼆点,⼀定要有代码分层的概念。有了分层的思想后,写代码 时⼀定要搞清楚代码的职责,将它放在职责对应的代码⽬录内。应⽤ 层代码主要完成服务组合和编排,以及聚合之间的协作,它是很薄的 ⼀层,不应该有核⼼领域逻辑代码。领域层是领域模型的业务的核 ⼼,领域模型的核⼼逻辑代码⼀定要在领域层实现。如果将核⼼领域 逻辑代码放到应⽤层,你的基于DDD分层架构模型的微服务可能会慢 慢变回原来紧耦合的传统三层架构,这样是不利于未来微服务架构的 演进的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1942475.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#初级——输出语句和转义字符

输出语句 在C#中,C#的输出语句是通过Console类进行输出,该类是一个在控制台下的一个标准输入流、输出流和错误流。使用该类下的Write()函数,即可打印要输出的内容。 Console.Write("Hello World!"); //在控制台应用中打印Hell…

websocket状态机

websocket突破了HTTP协议单向性的缺陷,基于HTTP协议构建了双向通信的通道,使服务端可以主动推送数据到前端,解决了前端不断轮询后台才能获取后端数据的问题,所以在小程序和H5应用中被广泛使用。本文主要集合报文分析对于websocket…

Python 机器学习求解 PDE 学习项目——PINN 求解一维 Poisson 方程

本文使用 TensorFlow 1.15 环境搭建深度神经网络(PINN)求解一维 Poisson 方程: − Δ u f in Ω , u 0 on Γ : ∂ Ω . \begin{align} -\Delta u & f \quad & \text{in } \Omega,\\ u & 0 \quad & \text{on } \Gamma:\partial \Om…

2024.7.22(nfs、samba)

一、web_server作用是发布nginx的web项目 1、停用selinux关闭防火墙 [rootnfs_server ~]# setenforce 0 [rootnfs_server ~]# vim /etc/selinux/config [rootnfs_server ~]# systemctl stop firewalld [rootnfs_server ~]# systemctl disable firewalld 2、安装nginx [rootwe…

四、GD32 MCU 常见外设介绍 (4) EXTI 中断介绍

4.EXTI 中断介绍 EXTI(中断/事件控制器)包含多个相互独立的边沿检测电路并且能够向处理器内核产生中断请求或唤醒事件。 EXTI 有三种触发类型:上升沿触发、下降沿触发和任意沿触发。 EXTI中的每一个边沿检测电路都可以独立配置和屏蔽。 4.1.GD32 EXTI 外设原理简介…

Nginx Rewrite(企业网站架构部署与优化)

Nginx Rewrite介绍 本章结构 实验步骤; 先在服务器1上写三个location;且等级各不相同; 如下;先将之前的location注释掉,避免冲突; 重启服务后生效; 如果用户输入的域名后只加了一个/或/都没有…

深入浅出C语言指针(进阶篇)

深入浅出C语言指针(基础篇) 深入浅出C语言指针(进阶篇) 目录 引言 一、指针和数组 1.数组名的理解 2.指针访问数组 3.一维数组传参的本质 二、二级指针 1.二级指针的概念 2.二级指针的内存表示 3.二级指针的解引用 三、字符指针 1.指针指向单个字符 2.指针指向字…

JavaWeb(4)JavaScript入门2—— JS的对象和JSON

一、JS的对象 1.声明语法1 通过new Object()直接创建对象 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><ti…

Linux——vi和vim编辑器

目录 基本介绍 vi和vim常用的三种模式 vi和vim的常用快捷键 基本介绍 vi和vim常用的三种模式 vi和vim的常用快捷键 网上找的快捷键盘图

docker搭建ES 8.14 集群

参考&#xff1a;【docker搭建es8集群kibana】_docker 安装生产级 es 8.14 集群-CSDN博客 1、之前已搭建一台单机版的dockerES集群 参见 Elasticsearch docker 安装_docker 安装es8.14.3-CSDN博客 2、现在需要重新搭建为docker ES集群 准备新搭建3个点 一、准备工作 提前开…

txt格式单词导入有道词典生词本 (java代码方式)

txt格式单词导入有道词典生词本 (java代码方式) 首先要求txt文档里单词的格式&#xff0c;大概需要像这种&#xff1a; 每行是一个单词&#xff0c;格式为&#xff1a;英文单词空格词性单词意思。 注意 导出单词本的名字就是你 txt 文件的名字 我这里是 公共英语三级 单词本 …

WPF项目实战视频《二》(主要为prism框架)

14.prism框架知识&#xff08;1&#xff09; 使用在多个平台的MVVM框架 新建WPF项目prismDemo 项目中&#xff1a;工具-NuGet包管理&#xff1a;安装Prism.DryIoc框架 在git中能看Prism的结构和源代码&#xff1a;git链接地址 例如&#xff1a;Prism/src/Wpf/Prism.DryIoc.Wpf…

Linux中tomcat下载教程

一.安装tomcat 1.安装 EPEL 仓库&#xff1a; sudo yum install epel-release2.安装 Tomcat&#xff1a; sudo yum install tomcat3.启动 Tomcat 服务&#xff1a; sudo systemctl start tomcat4.启用 Tomcat 服务开机启动&#xff1a; sudo systemctl enable tomcat5.检查…

SpringCloud 环境工程搭建

SpringCloud 环境&工程搭建 文章目录 SpringCloud 环境&工程搭建1. SpringCloud介绍2. 服务拆分原则2.1 单一职责原则2.2 服务自治2.3 单向依赖2.4 服务拆分示例 3. 数据准备4. 工程搭建4.1 创建父工程4.2 创建子工程4.2.1 子项目-订单服务4.2.2 子项目-商品服务 4.3 完…

物联网专业创新人才培养体系的探索与实践

一、引言 随着物联网&#xff08;IoT&#xff09;技术的迅猛发展&#xff0c;物联网领域的人才需求日益增加。物联网技术作为新一轮信息技术革命的核心&#xff0c;已经渗透到社会生活的各个领域&#xff0c;对推动经济转型升级、提升国家竞争力具有重要意义。因此&#xff0c…

Redis 7.x 系列【26】集群模式动态扩容、动态缩容

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 动态扩容1.1 安装、启动1.2 加入新节点1.3 分配哈希槽1.4 加入从节点 2. 缩容2.1 删…

PHP场地预约共享茶室棋牌室小程序系统源码

&#x1f375;&#x1f3b2;【聚会新宠】场地预约神器&#xff0c;共享茶室棋牌室小程序大揭秘&#xff01;&#x1f389; &#x1f3e1;【开篇&#xff1a;告别繁琐&#xff0c;聚会新选择】&#x1f3e1; 还在为找不到合适的聚会场地而烦恼吗&#xff1f;想要一个既私密又舒…

python+onlyoffice+vue3项目实战20240722笔记,环境搭建和前后端基础代码

开发后端 先创建data目录,然后在data目录下创建一个test.docx测试文档。 后端代码: import json import req import api from api import middleware, PlainTextResponseasync def doc_callback(request):data = await api.req.get_json(request)print("callback ==…

微信小程序-CANVAS写入图片素材、文字等数据生成图片

微信小程序中&#xff0c;CANVAS写入图片素材、文字等数据生成图片&#xff0c;最终可将生成的 base64 格式图片保存至相册操作 Tips&#xff1a; 1、canvas 标签默认宽度 300px、高度 150px canvas 生成图片时&#xff0c;写入图片素材、文字等数据前&#xff0c;需要根据实…

git的一些使用技巧(git fetch 和 git pull的区别,git merge 和 git rebase的区别)

最近闲来无聊&#xff0c;虽然会使用git操作&#xff0c;但是 git fetch 和 git pull 的区别&#xff0c;git merge 和 git rebase的区别只是一知半解&#xff0c;稍微研究一下&#xff1b; git fetch 和 git pull 的区别 git fetch git fetch 是将远程仓库中的改动拉到本地…