14、如何⽤DDD设计微服务代码模型
在完成领域模型设计后,接下来我们就可以开始微服务的设计和 落地了。在微服务落地前,⾸先要确定微服务的代码结构,也就是我 下⾯要讲的微服务代码模型。
只有建⽴了标准的微服务代码模型和代码规范后,我们才可以将 领域对象映射到代码对象,并将它们放⼊合适的代码⽬录结构中。标 准的代码模型可以让项⽬团队成员更好地理解代码,根据统⼀的代码 规范实现团队协作,也可以让微服务各层的业务逻辑互不⼲扰、分⼯ 协作、各据其位、各司其职,避免不必要的代码混淆,还可以让你在 微服务架构演进时,轻松完成代码重构。
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分层架构模型的微服务可能会慢 慢变回原来紧耦合的传统三层架构,这样是不利于未来微服务架构的 演进的。
相关文章:

14、如何⽤DDD设计微服务代码模型
在完成领域模型设计后,接下来我们就可以开始微服务的设计和 落地了。在微服务落地前,⾸先要确定微服务的代码结构,也就是我 下⾯要讲的微服务代码模型。 只有建⽴了标准的微服务代码模型和代码规范后,我们才可以将 领域对象映射到…...
ArcGIS Pro SDK (九)几何 12 多面体
ArcGIS Pro SDK (九)几何 12 多面体 文章目录 ArcGIS Pro SDK (九)几何 12 多面体1 通过拉伸多边形或折线构建多面体2 多面体属性3 构建多面体4 通过MultipatchBuilderEx构建多面体5 从另一个多面体构建多面体6 从 3D 模型文件构建…...

二次元手游《交错战线》游戏拆解
交错战线游戏拆解案 游戏亮点即核心趣味 一、关键词: 回合制游戏、二次元、机甲、横板、剧情、养成、异星探索。 二、游戏亮点: 符合目标群体审美的原画。 三、核心趣味: 抽卡、肝或者氪金解锁新皮肤。 核心玩法及系统规则 核心玩法&…...

【BUG】已解决:Downgrade the protobuf package to 3.20.x or lower.
Downgrade the protobuf package to 3.20.x or lower. 目录 Downgrade the protobuf package to 3.20.x or lower. 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英杰,211科班出身…...

Java开发之Redis
1、非关系型数据库、快、高并发、功能强大 2、为什么快?内存单线程 非阻塞的IO多路复用有效的数据类型/结构 3、应用:支持缓存、支持事务、持久化、发布订阅模型、Lua脚本 4、数据类型: 5 种基础数据类型:String(字…...

Java面试八股之 Spring Bean的生命周期
Spring Bean的生命周期 实例化(Instantiation):Spring容器根据Bean定义信息创建Bean的实例,通常通过无参构造函数进行。 依赖注入(Dependency Injection,DI):Spring容器按照Bean定…...
SQL中的函数
目录 前言 一、系统内置函数 1、数学函数 2、日期和时间函数 3、聚合函数 4、字符串函数 二、自定义函数 1、标量函数的创建与调用 2、内嵌表值函数的创建与调用 3、多语句表值函数的创建与调用 前言 函数是由一个或多个 T-SQL 语句组成的子程序,可用于封…...

VSCode | 修改编辑器注释的颜色
1 打开VsCode的设置进入settings.json 2 添加如下代码 "editor.tokenColorCustomizations": {"comments": "#17e917"},3 保存即可生效...

媒体邀约专访与群访的区别?
传媒如春雨,润物细无声,大家好,我是51媒体网胡老师。 媒体邀约中的专访与群访在多个方面存在显著差异,以下是对这两种采访方式的详细比较: 一、定义与形式 专访: 定义:专访是指由媒体记者对单…...

Pycharm2024最新版community社区版下载安装配置,快速上手
第一步:下载 方法1:官网链接 https://www.jetbrains.com/pycharm/download/?sectionwindows .方法2:百度网盘 链接:https://pan.baidu.com/s/1ic2N5hUQ2m1Kmyr5nK9Jxw?pwd76dt 提取码:76dt --来自百度网盘超级…...
服务器选择租用还是托管?托管和租用哪个比较划算
在构建或扩展IT基础设施时,服务器作为关键组件,其选择方式——租用或托管,直接关系到企业的运营成本、灵活性、安全性及长期发展战略。本文将从技术、经济、安全等多个维度,深入解析这两种方案的优缺点,并探讨在何种情…...

智能制造·数字化工厂建设规划方案(65P)
获取完整PPT见下图 更多有关华为研发管理/IPD、MBSE、PLM、ERP、MES、数据治理、数字样机等方面免费解决方案、资料获取,请见下图...

ACM中国图灵大会专题 | 图灵奖得主Manuel Blum教授与仓颉团队交流 | 华为论坛:面向全场景应用编程语言精彩回顾
ACM 中国图灵大会(ACM Turing Award Celebration Conference TURC 2024)于2024年7月5日至7日在长沙举行。本届大会由ACM主办,in cooperation with CCF,互联网之父Vinton Cerf、中国计算机学会前理事长梅宏院士和廖湘科院士担任学术…...

k8s 公共服务
修改named.conf。修改第13行和第21行 下面是 named.rfc1912 修改位置,在最后 所以用cp -p 复制文件,保留权限 nslookup 回车,server是看哪个dns 在起作用 dns服务器要配置给所有公共服务节点和 k8s 节点 就在网络文件加个DNS2就行了&…...

【数据分析详细教学】全球气温变迁:一个多世纪的数据分析
全球气温变迁:一个多世纪的数据分析 1. 数据集选择与获取 数据可以从NASA的GISTEMP数据集获取,通常提供的格式有TXT和CSV。我们假设数据是以CSV格式提供。 2. 数据预处理 使用Python的pandas库读取数据并进行预处理。 import pandas as pd# 加载数…...
AV1技术学习:Reference Frame System
一、Reference Frames AV1 Codec 允许在其解码的帧缓冲区中最多允许保存 8 帧。对于一个编码帧,可以从解码的帧缓冲区中选择任意 7 个帧作为它的参考帧。编码端可以通过比特流显式地传输参考帧索引,范围从 1到 7。原则上,参考帧索引 1-4 为当…...

数学建模(7)——Logistic模型
一、马尔萨斯人口模型 import numpy as np import matplotlib.pyplot as plt# 初始人口 N0 100 # 人口增长率 r 0.02 # 时间段(年) t np.linspace(0, 200, 200)# 马尔萨斯人口模型 N N0 * np.exp(r * t)# 绘图 plt.plot(t, N, labelPopulation) plt.…...

“微软蓝屏”事件,给IT行业带来的宝贵经验和教训
“微软蓝屏”事件是指2024年7月19日发生的一次全球性技术故障,主要涉及微软视窗(Windows)操作系统及其相关应用和服务。 以下是对该事件的详细解析: 一、事件概述 发生时间:2024年7月19日事件影响:全球多个…...

QT总结——图标显示坑
最近写代码遇到一个神仙大坑,我都怀疑我软件是不是坏了,这里记录一下。 写qt工程的时候我们一般会设置图标,这个图标是窗体的图标同时也是任务栏的图标,但是我发现生成的exe没有图标,这个时候就想着给他加一个图标&…...

SQL 注入漏洞详解 - Union 注入
1)漏洞简介 SQL 注入简介 SQL 注入 即是指 Web 应用程序对用户输入数据的合法性没有判断或过滤不严,攻击者可以在 Web 应用程序中事先定义好的查询语句的结尾上添加额外的 SQL 语句,在管理员不知情的情况下实现非法操作,以此来实现欺骗数据库服务器执行非授权的任意查询,…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...

【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...
适应性Java用于现代 API:REST、GraphQL 和事件驱动
在快速发展的软件开发领域,REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名,不断适应这些现代范式的需求。随着不断发展的生态系统,Java 在现代 API 方…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
vue3 daterange正则踩坑
<el-form-item label"空置时间" prop"vacantTime"> <el-date-picker v-model"form.vacantTime" type"daterange" start-placeholder"开始日期" end-placeholder"结束日期" clearable :editable"fal…...

快速排序算法改进:随机快排-荷兰国旗划分详解
随机快速排序-荷兰国旗划分算法详解 一、基础知识回顾1.1 快速排序简介1.2 荷兰国旗问题 二、随机快排 - 荷兰国旗划分原理2.1 随机化枢轴选择2.2 荷兰国旗划分过程2.3 结合随机快排与荷兰国旗划分 三、代码实现3.1 Python实现3.2 Java实现3.3 C实现 四、性能分析4.1 时间复杂度…...

AD学习(3)
1 PCB封装元素组成及简单的PCB封装创建 封装的组成部分: (1)PCB焊盘:表层的铜 ,top层的铜 (2)管脚序号:用来关联原理图中的管脚的序号,原理图的序号需要和PCB封装一一…...