5.微服务代码模型

1.微服务代码模型

代码分层

在微服务代码模型里,我们分别定义了用户接口层、并分别为它们建立了interfaces、application、domain和infrastructure四个一级代码目录;

  • interfaces(用户接口层): 它主要存放用户接口层与前端应用交互、数据转换和交互相关的代码;
  • application(应用层): 它主要存放与应用层服务组合和编排相关的代码。应用服务和事件等代码会放在这一层目录里;
  • domain(领域层): 它主要存放与领域层核心业务逻辑相关的代码。聚合内的聚合根以及实体、方法、值对象、领域服务和事件等相关代码会放在这一层目录里;
  • infrastructure(基础层): 它主要存放与基础资源服务相关的代码;

代码目录

  • 用户接口层有assembler、 dto和facade三类;
  • 应用层有event和service。为每个聚合的应用服务设计一个应用服务类;
    对于多表关联的复杂查询,由于这种复杂查询不需要有领域逻辑和业务规则约束,因此不建议将这类复杂查询放在领域层的领域模型中,可以通过应用层的应用服务采用传统多表关联的SQL查询方式;
  • 领域层有entity、event、 repository和service四个子目录;
    domain下的目录结构是由一个或多个独立的聚合目录构成,每一个聚合是一个独立的业务功能单元,多个聚合共同实现领域模型的核心业务逻辑。仓储设计时有—个重要原则: 就是一个聚合只能有一个仓储;
  • 基础层有config和util两个子目录;
    微服务代码目录结构

原则

第一点,聚合之间的代码边界一定要清晰。聚合之间的服务调用和数据关联应该尽可能松耦合和低关联,聚合之间的服务调用应该通过上层的应用层组合实现调用,原则上不允许聚合之间直接调用领域服务。这种松耦合的聚合代码关联,在以后业务发展和需求变更时,可以很方便地实现业务功能和聚合代码的重组,在微服务架构演进中将会起到非常重要的作用;
第二点,一定要有代码分层的概念。写代码时一定要搞清楚代码的职责,将它放在职责对应的代码目录内。应用层代码主要完成服务组合和编排,以及聚合之间的协作,它是很薄的一层,不应该有核心领域逻辑代码。领域层是领域模型的业务的核心,领域模型的核心逻辑代码一定要在领域层实现;

2.设计领域模型

领域层的领域对象

领域模型的聚合内一般会有聚合根、实体、值对象、命令和领域事件等领域对象。完成领域故事分析和微服务设计后,微服务的聚合内一般会有聚合根、实体、值对象、领域事件、领域服务、工厂和仓储、持久化对象等领域对象;

A.设计聚台根

  • 聚合根来源于领域模型,需要找出领域模型内与聚合根关联的所有实体和值对象;
  • 聚合根是一种特殊的实体,需要设计它的属性和方法。同时它也可以管理聚合内实体和值对象等领域对象的生命周期。聚合根可以引用聚合内的所有实体,也可以实现聚合之间的基于聚合根ID的引用;
  • 聚合根类放在领域层聚合的entity目录结构下;

B.设计实体

  • 在DDD分层架构里,实体类采用充血模型,在实体类内实现实体的全部业务逻辑。这些实体有自己的业务属性、方法和业务行为;
  • 大多数情况下,领域模型的实体对象与数据库持久化对象是一一对应的。但领域模型的某些实体在微服务没计时,可能会被设计为一个或多个数据持久化实体,或者实体的某些属性会被设计为值对象;
  • 实体类代码对象放在领域层聚合的entity目录结构下;

C.设计值对象

  • 如果这个领域对象在其他聚合内进行生命周期管理,并且引用它的实体对象只允许对它整体替换,我们就可以将它设计为值对象。如果这个领域对象有多条数据记录且需要基于它进行频繁的查询统计,则建议将它设计为实体;
  • 值对象类放在领域层聚合的entity目录结构下;

D.设计领域事件

  • 如果领域模型中领域事件会触发下一步业务操作,就需要设计领域事件;
  • 领域事件实体类放在领域层聚合的event目录结构下。领域事件的订阅建议放在应用层的event目录结构下。领域事件发布相关代码放在领域层或者应用层都是可以的;

E.设计领域服务

  • 领域服务通过对多个实体和实体方法进行组合和编排,完成多个实体组合的核心业务逻辑。领域服务是位于实体方法之上和应用服务之下的一层业务逻辑;
  • 如果实体方法需要被前端应用调用,需要将它封装成领域服务,然后再封装为应用服务;
  • 一个聚合可以建立一个领域服务类,可以将聚合中所有的领域服务都在这个领域服务类中实现。
  • 领域服务类放在领域层聚合的service目录结构下;

F.设计工厂租仓储

  • 一个聚合只有一个仓储。仓储包括仓储接口和仓储实现,通过依赖倒置原则实现应用业务逻辑与数据库资源逻辑的解耦;
  • 工厂类(factory)放在领域层聚合的service目录结构下。仓储相关代码放在领域层聚合的repository目录结构下;

G.设计持久化对象

  • 持久化对象PO主要完成DO对象的数据库持久化操作, PO一般与数据库表是一对一的关系。为了简化数据库设计,减少数据库表的数量,值对象往往以属性嵌入方式或序列化大对象方式嵌入实体表;
  • 持久化对象PO相关代码放在领域层聚合的repository目录结构下;

应用层的领域对象

应用层主要有应用服务和领域事件的发布和订阅;
在严格分层架构模式下,不允许服务的跨层调用,每个服务只能调用它紧邻的下一层服务。服务从下到上依次为:实体方法、领域服务、应用服务和facade接口;

  • 应用服务会对多个领域服务进行组合和编排,在用户接口层完成服务和数据封装后,就可以发布到API网关,供前端应用调用;
  • 应用服务类放在应用层scrvice目录结构下。领域事件的订阅处理逻辑放在应用层event目录结构下;
  • 服务类的命名参考以下规则: 一般一个聚合只有一个应用服务类,服务前面的名称就可以与聚合名保持一致,然后你可以用*DomainService或*AppService作为后缀,来区分它们是领域服务还是应用服务;

3.微服务调用过程

微服务服务封装

  • 在聚合内采用数据强一致性,在聚合之间采用数据最终一致性。在一次事务中,最多只能修攻一个聚合的数据。如果一次业务交易操作涉及了多个聚合数据的修改,那么应采用领域事件驱动机制。微服务内的领域事件通过事件总线完成聚合之间的异步处理,微服务之间的领域事件通过消息中间件完成。一个聚合对应一个聚合代码目录,聚合之间在代码完全隔离,它们通过应用层的应用服务来协调,完成不同聚合领域服务的组合和编排;
  • 实体采用充血模型,在实体类内部实现实体相关的所有业务逻辑,具体实现形式是实体类中的方法。实体是微服务内的原子业务对象,在设计时我们主要考虑实体自身的属性和业务行为,实现领域模型的核心基础能力。实体方法不会过多考虑外部操作和业务流程,保证领域模型的稳定性。聚合根引用实体和值对象,它可以协调聚合内的多个实体,在聚合根类方法中完成多实体的复杂业务逻辑。但为了职责和边界清晰,建议聚合根自身的业务行为在聚合根类方法中实现,而由多个实体组合实现的业务逻辑由聚合内的领域服务完成;
  • DDD提倡富领域模型,尽量将业务逻辑归属到实体对象上,实在无法归属的部分则设计成领域服务。领域服务会对多个实体或实体方法进行组装和编排,实现跨多个实体的复杂核心业务逻辑。领域服务是介于实体和应用服务之间的薄薄的一层,它的主要职能是实现领域层复杂核心领域逻辑的组合和封装。在领域服务或实体方法中,尽量不要调用其他聚合的领域服务或引用其他聚合的实体或值对象;
  • 应用服务用于组合和编排的服务,主要来源于领域服务,也可以来源于外部微服务的应用服务。除了完成服务的组合和编排外,应用服务内还可以完成安全认证、权限校验、初步的数据校验和分布式事务控制等功能;
    微服务服务封装

微服务数据形态

微服务数据形态

4.微服务解耦策略

微服务之间解耦策略

  • 限界上下文实现了不同业务领域边界的微服务物理边界的解耦;
  • 聚合实现了微服务内不同聚合之间逻辑边界的解耦;
  • 微服务之间通过领域事件和消息中间件,以数据最终—致性的策略,实现了微服务之间的异步调用利服务解耦;
  • 通过适当的数据冗余设计,如值对象的业务快照数据设计,实现了跨微服务不同聚合之间的数据解锅;

微服务内的解耦策略

  • DDD分层架构,通过分层和不同层的职责边界定义,实现了微服务内各层职能和代码的解耦;
  • 用户接口层通过facade接口和数据组装适配,实现了微服务核心业务逻辑与前端应用或用户解耦;
  • 仓储模式通过依赖倒置策略,实现了核心领域逻辑与基础资源处理逻辑的解耦;
  • 微服务代码目录通过聚合目录和分层目录代码边界,实现了不同职能代码边界的解耦,有利于微服务架构演进时代码的组合和拆分;
  • 应用服务通过对不同聚合领域服务的组合和编排,实现了同一个微服务内不同聚合的解耦;
  • 聚合之间通过聚合根ID引用,而不是对象引用方式,完成不同聚合领域对象之间的访问,实现了聚合之间不同领域对象的解耦;
  • 微服务内聚合之间通过事件总线,采用数据最终一致性策略,实现了聚合之间服务同步调用的解耦;

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

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

相关文章

Ultra ISO 虚拟光驱修改光盘盘符

windows xp 环境 ultra iso 虚拟光驱修改光盘盘符 method 1. 在ultra iso 中 [选项]->[配置]->[虚拟光驱],在新盘符里选指定盘符 ->[修改] method 2. 打开命令行,进入安装目录,如 "C:\Program Files\UltraISO\drivers"&…

Vue3复习笔记

目录 挂载全局属性和方法 v-bind一次绑定多个值 v-bind用在样式中 Vue指令绑定值 Vue指令绑定属性 动态属性的约束 Dom更新时机 ”可写的“计算属性 v-if与v-for不建议同时使用 v-for遍历对象 数组变化检测 事件修饰符 v-model用在表单类标签上 v-model还可以绑定…

【LMM 002】大型语言和视觉助手 LLaVA-1.5

论文标题:Improved Baselines with Visual Instruction Tuning 论文作者:Haotian Liu, Chunyuan Li, Yuheng Li, Yong Jae Lee 作者单位:University of Wisconsin-Madison, Microsoft Research, Columbia University 论文原文:htt…

JavaScript的三种引入的方式

目录 (一).什么是JS1.1JS的特点1.2JS的组成 (二).JS引用的三种方式2.1标签引用(或嵌入式)2.2文件引用(外链式)2.3行内式 (三).JS三种引用方式的优缺点1.行内方式:2.标签引用(或嵌入式):3.文件引…

怎么获取客户端真实IP?GO

在使用 Golang 的 net/rpc 包进行 RPC 服务开发时,我们有时候会遇到需要获取客户端的真实 IP 和当前连接 net.Conn 的需求。然而在 net/rpc 的服务处理方法中,并没有提供直接获取到这些信息的途径。 那么,我们应该如何去获取这些信息呢&…

如何高效查询文件:Linux 下的多种方法详解

如何高效查询文件:Linux 下的多种方法详解 在日常工作中,我们经常需要查找文件,无论是寻找特定的代码文件、配置文件还是其他文档。Linux 提供了多种强大的命令和工具,通过巧妙地使用管道符,我们可以将这些命令组合起来…

连锁门店管理需要信息化系统

连锁门店管理的信息化系统可以提供以下功能,以满足连锁企业日常管理的需求: 1. 连锁线下收银:信息化系统可以提供线下收银功能,包括商品扫码、价格结算、支付方式选择等。通过系统记录每笔交易数据,方便对销售情况进行…

【基于VirtualBox及openEuler20.03 TLS SP1编译openGauss2.1.0源码】

【openEuler 20.03 TLS编译openGauss2.1.0源码】 一、安装环境二、安装步骤 一、安装环境 项目Value虚拟机virtualbox操作系统openEuler 20.03 TLSopenGauss2.1.0openGauss-third_party2.1.0 二、安装步骤 以下操作需要在root用户下执行 编辑/etc/selinux/config vim /etc/s…

C++程序编译

GCC编译器 文章目录 GCC编译器 源文件 为 Main.cpp 注意cpp文件 一定要用g命令 否则没办法执行 预处理(Pre-Processing):首先会经过预处理器将程序中的预编译指令进行处理,然后把源文件中的注释这些没用的东西都给扬了。 g -E Mai…

JVM系列-方法区、堆区、栈区

在 Java 中,内存主要分为方法区、堆区和栈区,每个区域负责不同类型的数据和任务。以下是它们的主要特征: 1. 方法区(Method Area) 方法区是 JVM 的一部分,用于存储类的元数据信息、静态变量、常量池等。在…

【拼题A】2024跨年挑战赛

文章目录 跨年-1 特殊的年份输入格式:输出格式:C代码 跨年-2 穿什么衣服输入格式:输出格式:输入样例:输出样例:C 代码 跨年-3 按比例发奖输入格式:输出格式:输入样例:输出样例:C代码 跨年-4 骗钱的手机游戏输入格式:输出格式:输入样例:输出样例:C代码 跨年-5 找年兽输入格式:输…

Qt6.5示例:QMainWindow集成QMenuBar菜单栏

欢迎关注公众号(20YC编程),有免费C视频课程哦! -今日内容- 1 QMenuBar简介 QMenuBar是Qt框架中的一个菜单栏类,它提供了一个可以包含一个或多个QAction对象或级联的QMenu对象的菜单栏。 QMenuBar通常被放置在主窗口的标题栏下方&#xff0…

消息队列LiteQueue

文章目录 一、简介二、设计2.1 队列结构设计2.2 队列接口设计 三、实现3.1 队列锁的实现3.2 创建队列3.3 写入队列3.4 读出数据3.5 判断队列是否为空3.6 判断队列是否为满3.7 清空队列3.8 删除队列 四、测试参考 一、简介 收到消息时先把接收到的消息放到队列中。在任务中从队…

63页!嵩山版Java开发手册分享

作为广受欢迎的编程语言之一,Java在软件开发领域扮演着重要的角色。然而,由于Java的灵活性和广泛应用,很容易出现代码质量低下、可读性差、维护困难等问题。为了解决这些问题,阿里巴巴集团发布了一份权威指南——阿里嵩山版Java开…

redis数据库高可用应用场景-配置哨兵

一,redis数据库哨兵的使用场景 Redis哨兵机制通常在需要高可用性的 Redis 环境中使用,如果是普通的项目,只是用来做缓存的可以忽略。 适用场景: 高可用性需求:当需要确保 Redis 服务的高可用性并且防止单点故障时&…

【2023年第十三届APMCM亚太地区大学生数学建模竞赛】A题 水果采摘机器人的图像识别 35页论文及python代码

【2023年第十三届APMCM亚太地区大学生数学建模竞赛】A题 水果采摘机器人的图像识别 1 题目 水果采摘机器人的图像识别 中国是世界上最大的苹果生产国,年产量约为3500万吨。与此同时,中国也是世界上最大的苹果出口国,世界上每两个苹果中就有…

iToF人脸识别

iToF(间接飞行时间)是一种测量光飞行时间的技术,主要应用于人脸识别。 iToF人脸识别技术在哪些场景下会用到 iToF人脸识别技术可以应用于许多场景,以下是一些常见的应用场景: 平安城市:在城市监控系统中,iToF人脸识别技术可以用于实时监控、目标检测和识别,以及异常行为…

iostat获取IO延迟单位从ms调整us的方案

iostat命令统计的磁盘I/O延迟通常是以毫秒(ms)为单位,例如在输出中的await字段表示的是平均服务时间,包括等待时间和处理时间,这个值就是以毫秒为单位。 然而,要获取更精确到微秒级别(us&#x…

Python爬虫---使用BeautifulSoup下载麦当劳点餐图片

步骤: 1. 导入需要使用的包 2. 定位正确的url地址 3. 发请求 4. 获取响应 5. 解析响应的内容 6. 将获取的xpath语法转换成bs4语法 7.下载图片 import urllib.request from bs4 import BeautifulSoup# url url "https://www.mcdonalds.com.cn/index/Fo…

WEB 3D技术 three.js通过光线投射 完成几何体与外界的事件交互

本文 我们来说 光线投射 光线投射技术是用于3维空间场景中的交互事件 我们先编写代码如下 import ./style.css import * as THREE from "three"; import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";const scene new THRE…