19、基于DDD的微服务代码详解

本章将深入探讨如何基于领域驱动设计(DDD)开发微服务代码,并提供具体的代码示例和详细解释。我们将基于第十八章中的请假案例进行讲解,确保每个细节都不放过。

1、项目背景

回顾第十八章中请假案例的需求和设计,我们已经拆分出两个微服务:请假服务和考勤服务。请假服务的核心业务流程如下:

  1. 请假人填写请假单提交审批。
  2. 根据请假人身份、请假类型和请假天数进行校验并确定审批规则。
  3. 根据审批规则确定审批人,逐级提交上级审批,核批通过则完成审批,核批不通过则退回申请人。

请假微服务使用了许多DDD的设计思想和方法,如聚合、实体、值对象、领域服务和仓储模式。

2、聚合中的对象

请假微服务包含三个聚合:请假(leave)、人员(person)和审批规则(rule)。我们将详细解释每个聚合中的对象及其职责。

2.1、聚合根

聚合根是聚合的入口,负责维护聚合内所有对象的一致性。对于请假聚合,LeaveApplication是聚合根。

聚合根示例代码:LeaveApplication.java

public class LeaveApplication {private String leaveId;private String applicantId;private String type;private int days;private String status;public LeaveApplication(String leaveId, String applicantId, String type, int days) {this.leaveId = leaveId;this.applicantId = applicantId;this.type = type;this.days = days;this.status = "PENDING";}public void approve() {if (!"PENDING".equals(this.status)) {throw new IllegalStateException("Leave application is not in a pending state");}this.status = "APPROVED";}public void reject() {if (!"PENDING".equals(this.status)) {throw new IllegalStateException("Leave application is not in a pending state");}this.status = "REJECTED";}// Getters and setters
}
2.2、实体

实体是具有唯一标识的对象,其生命周期和状态会发生变化。在请假聚合中,LeaveApplication本身也是一个实体,因为它具有唯一的leaveId

2.3、值对象

值对象是不可变的对象,只包含属性,用于描述领域中的特征。在请假聚合中,可以定义LeaveType作为值对象,表示请假的类型。

值对象示例代码:LeaveType.java

public class LeaveType {private final String type;public LeaveType(String type) {this.type = type;}public String getType() {return type;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;LeaveType leaveType = (LeaveType) o;return Objects.equals(type, leaveType.type);}@Overridepublic int hashCode() {return Objects.hash(type);}
}
2.4、领域服务

领域服务封装核心业务逻辑,实现需要多个实体协作的领域逻辑。在请假聚合中,审批逻辑可以被封装到一个领域服务中。

领域服务示例代码:LeaveApprovalService.java

public class LeaveApprovalService {private final LeaveRepository leaveRepository;public LeaveApprovalService(LeaveRepository leaveRepository) {this.leaveRepository = leaveRepository;}public void approveLeave(String leaveId) {LeaveApplication leaveApplication = leaveRepository.findById(leaveId);if (leaveApplication == null) {throw new IllegalArgumentException("Leave application not found");}leaveApplication.approve();leaveRepository.save(leaveApplication);}public void rejectLeave(String leaveId) {LeaveApplication leaveApplication = leaveRepository.findById(leaveId);if (leaveApplication == null) {throw new IllegalArgumentException("Leave application not found");}leaveApplication.reject();leaveRepository.save(leaveApplication);}
}
3、领域事件

领域事件是领域驱动设计中解耦的重要手段,通过事件机制实现领域对象之间的松耦合。

3.1、领域事件基类

领域事件基类定义了领域事件的基本结构和属性。

领域事件基类示例代码:DomainEvent.java

public abstract class DomainEvent {private final LocalDateTime occurredOn;protected DomainEvent() {this.occurredOn = LocalDateTime.now();}public LocalDateTime getOccurredOn() {return occurredOn;}
}
3.2、领域事件实体

具体的领域事件实体继承自领域事件基类,表示具体的业务事件。

领域事件实体示例代码:LeaveApprovedEvent.java

public class LeaveApprovedEvent extends DomainEvent {private final String leaveId;private final String applicantId;public LeaveApprovedEvent(String leaveId, String applicantId) {this.leaveId = leaveId;this.applicantId = applicantId;}public String getLeaveId() {return leaveId;}public String getApplicantId() {return applicantId;}
}
3.3、领域事件的执行逻辑

领域事件的执行逻辑可以通过事件发布器和事件处理器实现。

事件发布器示例代码:EventPublisher.java

public class EventPublisher {private final List<EventSubscriber> subscribers = new ArrayList<>();public void subscribe(EventSubscriber subscriber) {subscribers.add(subscriber);}public void publish(DomainEvent event) {for (EventSubscriber subscriber : subscribers) {subscriber.handle(event);}}
}

事件处理器示例代码:LeaveApprovedEventHandler.java

public class LeaveApprovedEventHandler implements EventSubscriber {@Overridepublic void handle(DomainEvent event) {if (event instanceof LeaveApprovedEvent) {LeaveApprovedEvent leaveApprovedEvent = (LeaveApprovedEvent) event;// 处理请假批准事件的逻辑}}
}
3.4、领域事件数据持久化

为了保证事件的持久化,可以将事件存储到数据库中。

事件持久化示例代码:EventStore.java

public class EventStore {private final List<DomainEvent> events = new ArrayList<>();public void save(DomainEvent event) {events.add(event);}public List<DomainEvent> findAll() {return new ArrayList<>(events);}
}
4、仓储模式

仓储模式用于管理聚合的持久化和检索,通过依赖倒置原则实现基础资源和业务逻辑的解耦。

4.1、DO与PO对象的转换

在持久化过程中,需要将领域对象(DO)转换为持久化对象(PO),以适应不同的持久化需求。

DO与PO转换示例代码:LeaveMapper.java

public class LeaveMapper {public static LeaveApplication toDomain(LeavePO po) {return new LeaveApplication(po.getLeaveId(), po.getApplicantId(), po.getType(), po.getDays());}public static LeavePO toPersistence(LeaveApplication domain) {LeavePO po = new LeavePO();po.setLeaveId(domain.getLeaveId());po.setApplicantId(domain.getApplicantId());po.setType(domain.getType());po.setDays(domain.getDays());return po;}
}
4.2、仓储实现逻辑

仓储实现负责具体的持久化操作,可以使用JPA或其他ORM框架。

仓储实现示例代码:LeaveRepository.java

public interface LeaveRepository {LeaveApplication findById(String leaveId);void save(LeaveApplication leaveApplication);
}@Repository
public class JpaLeaveRepository implements LeaveRepository {@Autowiredprivate LeaveJpaRepository leaveJpaRepository;@Overridepublic LeaveApplication findById(String leaveId) {LeavePO po = leaveJpaRepository.findById(leaveId).orElse(null);return po == null ? null : LeaveMapper.toDomain(po);}@Overridepublic void save(LeaveApplication leaveApplication) {LeavePO po = LeaveMapper.toPersistence(leaveApplication);leaveJpaRepository.save(po);}
}public interface LeaveJpaRepository extends JpaRepository<LeavePO, String> {}
5、 工厂模式

工厂模式用于创建复杂的聚合根对象,封装其创建过程,确保对象的一致性。

工厂模式示例代码:LeaveFactory.java

public class LeaveFactory {public static LeaveApplication createLeave(String applicantId, String type, int days) {String leaveId = UUID.randomUUID().toString();return new LeaveApplication(leaveId, applicantId, type, days);}
}
6、服务的组合与编排

服务的组合与编排通过应用服务实现,将领域服务和基础服务组合起来,实现复杂的业务流程。

应用服务示例代码:LeaveApplicationService.java

@Service
public class LeaveApplicationService {@Autowiredprivate LeaveRepository leaveRepository;@Autowiredprivate LeaveApprovalService leaveApprovalService;public void applyLeave(String applicantId, String type, int days) {LeaveApplication leaveApplication = LeaveFactory.createLeave(applicantId, type, days);leaveRepository.save(leaveApplication);}public void approveLeave(String leaveId) {leaveApprovalService.approveLeave(leaveId);}public void rejectLeave(String leaveId) {leaveApprovalService.rejectLeave(leaveId);}
}
7、微服务拆分时的代码调整

在微服务架构演进过程中,需要对代码进行重构和调整,以适应新的架构需求。

7.1、微服务拆分前的代码

在拆分前,所有功能都集中在一个单体应用中,代码耦合度高,难以维护和扩展。

public class LeaveApplicationService {// 包含所有业务逻辑和持久化操作
}
7.2、微服务拆分后的代码

在拆分后,功能模块化,代码解耦,每个微服务独立负责特定的业务领域。

public class LeaveApplicationService {@Autowiredprivate LeaveRepository leaveRepository;@Autowiredprivate LeaveApprovalService leaveApprovalService;// 只负责业务逻辑,持久化操作由仓储负责
}
8、服务接口的提供

微服务对外提供接口,以便其他服务或前端应用进行调用。接口设计需要考虑到数据传输对象(DTO)和视图对象(VO)的转换。

8.1、facade接口

facade接口用于封装复杂的业务逻辑,对外提供统一的服务接口。

facade接口示例代码:LeaveFacade.java

@RestController
@RequestMapping("/leaves")
public class LeaveFacade {@Autowiredprivate LeaveApplicationService leaveApplicationService;@PostMappingpublic ResponseEntity<Void> applyLeave(@RequestBody LeaveDto leaveDto) {leaveApplicationService.applyLeave(leaveDto.getApplicantId(), leaveDto.getType(), leaveDto.getDays());return new ResponseEntity<>(HttpStatus.CREATED);}@PutMapping("/{leaveId}/approve")public ResponseEntity<Void> approveLeave(@PathVariable String leaveId) {leaveApplicationService.approveLeave(leaveId);return new ResponseEntity<>(HttpStatus.OK);}@PutMapping("/{leaveId}/reject")public ResponseEntity<Void> rejectLeave(@PathVariable String leaveId) {leaveApplicationService.rejectLeave(leaveId);return new ResponseEntity<>(HttpStatus.OK);}
}
8.2、DTO数据组装

DTO用于数据传输,简化前端与后端的交互,避免领域对象的直接暴露。

DTO示例代码:LeaveDto.java

public class LeaveDto {private String applicantId;private String type;private int days;// Getters and setters
}
9、微服务解耦策略小结

通过本章代码详解,我们了解了用DDD设计和开发的微服务代码具体实现,重点关注了聚合、实体、值对象、领域服务、领域事件、仓储模式和工厂模式等DDD概念的实现细节。我们还探讨了微服务拆分过程中的代码调整和服务接口的设计。

解耦策略总结

  1. 聚合内解耦:通过聚合根管理聚合内对象的一致性,避免直接引用。
  2. 聚合间解耦:通过事件总线实现聚合间的异步通信,避免直接依赖。
  3. 服务解耦:通过领域服务和应用服务分层实现业务逻辑和持久化操作的解耦。
  4. 数据传输解耦:通过DTO和VO实现前后端的数据解耦。

本章小结

本章详细介绍了基于DDD的微服务代码实现,包括聚合中的对象、领域事件、仓储模式、工厂模式、服务的组合与编排以及微服务拆分时的代码调整。通过这些具体的代码示例和解释,读者可以深入理解DDD在微服务开发中的应用,并在实际项目中灵活运用这些知识和技能。

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

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

相关文章

“八股文”在实际工作中是助力、阻力还是空谈?

一&#xff1a;浅谈 关于“八股文”在程序员面试中的重要性和实际工作中的作用&#xff0c;确实是一个引发广泛讨论的话题。以下是我对这个问题的看法&#xff1a; 1. “八股文”的定义与特征 “八股文”通常指的是面试中常见的标准化问答或经典理论知识&#xff0c;例如…

Apollo:源码分析之cyber/mainboard启动入口介绍-my write, test ok

软件结构图 cyber入口 cyber的入口在"cyber/mainboard"目录中: ├── mainboard.cc // 主函数 ├── module_argument.cc // 模块输入参数 ├── module_argument.h ├── module_controller.cc // 模块加载,卸载 └── module_controller.…

关于Docker Engine AuthZ 插件授权绕过漏洞 (CVE-2024-41110)

一、漏洞概述 漏洞名称&#xff1a;Docker Engine AuthZ 插件授权绕过漏洞 &#xff08;CVE-2024-41110&#xff09; 漏洞等级&#xff1a;高危 漏洞描述&#xff1a;DockerEngine是Docker的核心组件&#xff0c;是一 个开源的容器引擎&#xff0c;负责构建、运行和管理容器…

【Vue】权限控制

权限管理 分类&#xff1a; 页面权限功能(按钮)权限接口权限 vue3-element-admin 的实现方案 一般我们在业务中将 路由可以分为两种&#xff0c;constantRoutes 和 asyncRoutes。 constantRoutes&#xff1a; 代表那些不需要动态判断权限的路由&#xff0c;如登录页、404(或…

【echarts】 柱状图,最后带“竖线”

具体&#xff1a; https://echarts.zhangmuchen.top/#/detail?cid28ea6-0601-e9f5-9cc29-c022b758 let data [{value: 0,name: 数据格式一},{value: 55,name: 数据格式二},{value: 66,name: 数据格式三},{value: 75,name: 数据格式四},{value: 20,name: 数据格式五}];getAr…

盘点.软件测试模型

软件开发模型   软件开发模型(Software Development Model)是指软件开发全部过程、活动和任务的结构框架。软件开发包括需求、设计、编码和测试等阶段&#xff0c;有时也包括维护阶段。 软件开发模型能清晰、直观地表达软件开发全过程&#xff0c;明确规定了要完成的主要活动…

C++类与对象-六大成员函数

默认成员函数就是用户没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个空类编译器会默认⽣成8个默认成员函数。本文只介绍其中6个&#xff0c;C11增加两个函数见后续博客。 目录 一、构造函数 1.1 概念 1.2 特性 1.3 使用举例 1.4 初始化列表 1…

如何通过前端表格控件实现自动化报表?

背景 最近伙伴客户的项目经理遇见一个问题&#xff0c;他们在给甲方做自动化报表工具&#xff0c;项目已经基本做好了&#xff0c;但拿给最终甲方&#xff0c;业务人员不太买账&#xff0c;项目经理为此也是天天抓狂&#xff0c;没有想到合适的应对方案。 现阶段主要面临的问…

docker笔记7-dockerfile

docker笔记7-dockerfile 一、dockerfile介绍二、dockerfile指令三、构建自己的镜像 一、dockerfile介绍 Dockerfile是用来构建Docker镜像的构建文件&#xff0c;是由一系列命令和参数构成的脚本。 以下是常用的 Dockerfile 关键字的完整列表和说明&#xff1a; 二、docker…

【计算机毕业设计】838装修公司CRM系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

为什么要做边界值测试?

边界值测试的理解 边界值测试&#xff08;Boundary Value Testing&#xff09;是一种常用的软件测试方法&#xff0c;它侧重于测试输入值的边缘或临界条件。这些边缘条件通常包括最小值、最大值以及接近这些最小值和最大值的值。边界值测试的基本思想是&#xff0c;许多软件错…

React 学习——Context机制层级组件通信

核心思路&#xff1a;&#xff08;适用于所有层级&#xff0c;不仅仅是爷孙 父子&#xff09; createContext方法创建一个上下文对象在顶层组件 通过Provider组件提供数据在底层组件&#xff0c;通过useContext钩子函数使用数据 import { createContext, useContext } from …

R语言 爬取数据+简单清洗

小小练习。见代码注释 # 加载必要的包 library(rvest) library(dplyr) library(tidyr)# 指定网页URL url <- "https://research.un.org/en/unmembers/scmembers"# 读取网页内容 webpage <- read_html(url)# 提取所有表格节点 table_nodes <- html_nodes(web…

基于人工智能及大数据的综合智能交通管理平台(可编辑30页PPT)

引言&#xff1a;随着城市化进程的加速和汽车保有量的快速增长&#xff0c;交通拥堵、交通事故频发以及交通资源分配不均等问题日益突出&#xff0c;成为制约城市发展的重要因素。为了应对这些挑战&#xff0c;基于人工智能&#xff08;AI&#xff09;及大数据技术的综合智能交…

【React】详解自定义 Hook

文章目录 一、自定义 Hook 的基本用法1. 什么是自定义 Hook&#xff1f;2. 创建自定义 Hook3. 使用自定义 Hook 二、自定义 Hook 的进阶应用1. 处理副作用2. 组合多个 Hook3. 参数化 Hook4. 条件逻辑 三、自定义 Hook 的实际应用案例1. 实现用户身份验证2. 实现媒体查询 四、最…

民大食堂用餐小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;商家管理&#xff0c;档口号管理&#xff0c;商家餐品管理&#xff0c;餐品种类管理&#xff0c;购物车管理&#xff0c;订单信息管理 微信端账号功能包括&#xff1a;系统首页&a…

angular入门基础教程(七)系统路由

路由的实现 当我们系统越来复杂&#xff0c;功能越来越多&#xff0c;路由也就是必须的了。在 ng 中如何实现路由呢&#xff1f; 启用路由 在 app 目录下&#xff0c;新建一个 router 目录&#xff0c;把 app.routers.ts 文件拷贝过来&#xff0c;并修改一下。 import { Ro…

C语言程序设计16

程序设计16 问题16_1代码16_1结果16_1 问题16_2代码16_2结果16_2 问题16_3代码16_3结果16_3 问题16_1 函数 f u n fun fun 的功能是&#xff1a;逆置数组元素中的值。 例如&#xff0c;若形参 a a a 所指数组中的数据最初排列为 &#xff1a; 1 , 2 , 3 , 4 , 5 , 6 …

高职院校大数据人才培养成果导向系统构建、实施要点与评量方法

一、引言 在当今信息化快速发展的背景下&#xff0c;大数据已成为推动社会进步和产业升级的重要力量。为满足社会对大数据人才的需求&#xff0c;高职院校纷纷开设大数据相关专业&#xff0c;并致力于探索科学有效的人才培养模式。本文立足于我国信息化与智能化发展趋势&#…

【初阶数据结构】10.排序(1)

文章目录 1.排序概念及运用1.1 概念1.2 运用1.3 常见排序算法 2. 实现常见排序算法2.1 插入排序2.1.1 直接插入排序2.1.2 希尔排序2.1.2.1 希尔排序的时间复杂度计算 2.2 选择排序2.2.1 直接选择排序2.2.2 堆排序 1.排序概念及运用 1.1 概念 排序&#xff1a;所谓排序&#x…