🎉 领域模型即服务 | Wow 2.16.16 发布
领域驱动 | 事件驱动 | 测试驱动 | 声明式设计 | 响应式编程 | 命令查询职责分离 | 事件溯源
更新内容
Wow 除了为命令(
Command
)自动生成了 OpenAPI 端点,另外还提供了查询(Query
) OpenAPI 端点。 这意味着开发人员通常只需专注于编写领域模型,即可完成服务开发,而无需费心处理查询逻辑的实现,极大提升了开发效率。
- 特性(query): 新增
SnapshotQueryServiceRegistrar
以支持自动将所有本地聚合根查询服务注册到Spring
容器中。 - 特性(query): 为
SnapshotQueryService
API 添加属性NamedAggregate
- 重构(compensation): 使用
QueryDSL
替换MongoExecutionFailedQuery
- 依赖(build): 升级
org.testcontainers:testcontainers-bom
版本 到v1.19.7
查询服务注册器
SnapshotQueryServiceRegistrar
用于自动将所有本地聚合根查询服务注册到 Spring
容器中。 开发者可以通过指定的 Bean Name
从 BeanFactory
中获取相应的 SnapshotQueryService
。
Bean Name
命名规则:聚合根名称 + ".SnapshotQueryService"
。
使用案例:
构造函数注入
class OrderService( @Qualifier("example.order.SnapshotQueryService") private val queryService: SnapshotQueryService<OrderState> ) { fun getById(id: String): Mono<OrderState> { return condition { id(id) }.single(queryService).toState() } }
字段注入
@Qualifier("example.order.SnapshotQueryService") @Autowired private lateinit var queryService: SnapshotQueryService<OrderState>
操作符
操作符 | 描述 |
---|---|
AND | 对提供的条件列表执行逻辑与 |
OR | 对提供的条件列表执行逻辑或 |
ID | 匹配id 字段值等于指定值的所有文档 |
IDS | 匹配id 字段值等于指定值列表中的任何值的所有文档 |
TENANT_ID | 匹配tenantId 字段值等于指定值的所有文档 |
DELETED | 匹配deleted 字段值等于指定值的所有文档 |
ALL | 匹配所有文档 |
EQ | 匹配字段名称值等于指定值的所有文档 |
NE | 匹配字段名称值不等于指定值的所有文档 |
GT | 匹配给定字段的值大于指定值的所有文档 |
LT | 匹配给定字段的值小于指定值的所有文档 |
GTE | 匹配给定字段的值大于或等于指定值的所有文档 |
LTE | 匹配给定字段的值小于或等于指定值的所有文档 |
CONTAINS | 匹配给定字段的值包含指定值的所有文档 |
IN | 匹配字段值等于指定值列表中的任何值的所有文档 |
NOT_IN | 匹配字段值不等于任何指定值或不存在的所有文档 |
BETWEEN | 匹配字段值在指定值范围区间的所有文档 |
ALL_IN | 匹配所有文档,其中字段值是包含所有指定值的数组 |
STARTS_WITH | 匹配字段值以指定字符串开头的文档 |
ENDS_WITH | 匹配字段值以指定字符串结尾的文档 |
ELEM_MATCH | 条件与包含数组字段的所有文档相匹配,其中数组中至少有一个成员与给定的条件匹配。 |
NULL | 匹配字段值在指定值为null 的所有文档 |
NOT_NULL | 匹配字段值在指定值不为null 的所有文档 |
TRUE | 匹配字段值在指定值为true 的所有文档 |
FALSE | 匹配字段值在指定值为false 的所有文档 |
RAW | 原始操作符,将条件值直接作为原始的数据库查询条件 |
TODAY | 匹配数值类型时间戳字段在今天范围区间的所有文档。比如:today 为 2024-06-06 ,匹配范围 2024-06-06 00:00:00.000 ~ 2024-06-06 23:59:59.999 的所有文档 |
TOMORROW | 匹配数值类型时间戳字段在昨天范围区间的所有文档。比如:today 为 2024-06-06 ,匹配范围 2024-06-05 00:00:00.000 ~ 2024-06-05 23:59:59.999 的所有文档 |
THIS_WEEK | 匹配数值类型时间戳字段在本周范围区间的所有文档 |
NEXT_WEEK | 匹配数值类型时间戳字段在下周范围区间的所有文档 |
LAST_WEEK | 匹配数值类型时间戳字段在上周范围区间的所有文档 |
THIS_MONTH | 匹配数值类型时间戳字段在本月范围区间的所有文档。比如:today : 2024-06-06 ,匹配范围 : 2024-06-01 00:00:00.000 ~ 2024-06-30 23:59:59.999 的所有文档 |
LAST_MONTH | 匹配数值类型时间戳字段在上月范围区间的所有文档。比如:today : 2024-06-06 ,匹配范围 : 2024-05-01 00:00:00.000 ~ 2024-05-31 23:59:59.999 的所有文档 |
RECENT_DAYS | 匹配数值类型时间戳字段在指定值最近天数范围区间的所有文档。比如:today : 2024-06-06 ,近三天,匹配范围 : 2024-06-04 00:00:00.000 ~ 2024-06-06 23:59:59.999 的所有文档。即 : 今天、昨天、前天 |
QueryDsl
通过 QueryDsl
,您可以轻松构建复杂的查询条件,例如:
pagedQuery { pagination { index(1) size(10) } sort { "field1".asc() } condition { all() not { "field1" eq "value1" "field2" ne "value2" } "filed3" gt 1 "field4" lt 1 "field5" gte 1 "field6" lte 1 "field7" like "value7" "field8" isIn listOf("value8") "field9" notIn listOf("value9") "field10" between (1 to 2) "field11" all listOf("value11") "field12" startsWith "value12" "field13" elemMatch { "field14" eq "value14" } "field15".isNull() "field16".notNull() "field17".isTrue() "field18".isFalse() and { "field3" eq "value3" "field4" eq "value4" } or { "field3" eq "value3" "field4" eq "value4" } } }
OpenAPI
以下是一个示例 curl
命令,用于执行查询:
curl -X 'POST' \ 'http://localhost:8080/execution_failed/snapshot/pagination' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "sort": [ { "field": "_id", "direction": "DESC" } ], "pagination": { "index": 1, "size": 10 }, "condition": { "field": "", "operator": "AND", "value": "", "children": [ { "field": "state.recoverable", "operator": "NE", "value": "UNRECOVERABLE", "children": [] }, { "field": "state.status", "operator": "NE", "value": "SUCCEEDED", "children": [] }, { "field": "state.isBelowRetryThreshold", "operator": "EQ", "value": false, "children": [] } ] } }'
TypeScript
在 TypeScript 中,您可以使用 Conditions
类来构建复杂的查询条件,例如:
Conditions.and( [ Conditions.ne(RECOVERABLE, UNRECOVERABLE), Conditions.ne(STATUS, SUCCEEDED), Conditions.eq(IS_BELOW_RETRY_THRESHOLD, false) ] )
简介
Wow 是一个基于领域驱动设计和事件溯源的现代响应式 CQRS 微服务开发框架,历经多年生产环境验证。
旨在帮助开发者构建现代化的、高性能且易于维护的微服务应用程序,充分发挥领域驱动设计和事件溯源等模式优势的同时降低应用的复杂性以及实践成本。
值得一提的是,领域驱动设计和事件溯源并非微服务架构的专属,Wow 框架不仅适用于微服务开发,同样也可用于构建基于领域驱动设计的单体应用程序。
快速开始
使用 Wow 项目模板快速创建基于 Wow 框架的 DDD 项目
特性概览
架构图
背景
随着业务的发展和复杂性的增加,传统的架构和开发方式逐渐显露出瓶颈。领域驱动设计和事件溯源等理念在提高系统设计的灵活性和可维护性方面表现出色,但在实践中常常需要面对复杂性和学习曲线的挑战。
Wow 框架的目标是以简单易用的方式将领域驱动设计和事件溯源等理念融入到微服务应用开发中,降低开发者的学习成本,提高开发效率。 通过提供现代响应式的 CQRS 架构和相关组件,Wow 框架旨在让开发者更专注于业务逻辑的实现,而不必过多关心底层技术细节。
经过多年的实践和不断的演进,Wow 框架在生产环境中得到了验证,积累了丰富的经验。这些经验和反馈不仅丰富了框架的功能和性能,也为持续的改进和优化提供了宝贵的指导。
对于开发者而言,Wow 框架意味着什么?
我曾告诫我的团队:如果我们过于依赖数据驱动设计而忽视领域驱动设计,我们最终将沦为 CRUD 工程师。
CRUD 工程师的竞争力和可替代性可想而知,这或许是为何会有 35 岁效应,企业显然更倾向于招募没有太多生活羁绊、更加廉价的 25 岁 CRUD 工程师。
业务价值
软件系统的核心价值体现在业务价值上,研发人员不应只关注技术实现上,而是应该更多地关注业务价值的实现。 这其中的好处显而易见,当你开发完一个业务系统之后,你将变成一个业务专家,甚至比跟你合作的领域专家还要专业,因为你需要洞察业务细节。
使用 Wow 框架,意味着你将关注点放在围绕领域模型设计上,与业务专家一起探索业务领域,而不是关注于技术实现上。 你仅需编写领域模型,即可完成服务开发,Wow 框架自动为你准备好 OpenAPI 接口。
在《实现领域驱动设计》一书中,作者 Vaughn Vernon 提到:核心域才值得投入精力进行领域驱动设计, 但如果你使用 Wow 框架,你将发现,因为低廉开发成本、快速的开发效率,即使是次要的支撑子域也值得 DDD。
性能与伸缩性
随着业务的发展,你需要开始思考系统的性能和伸缩性问题。 在传统架构中,这牵扯到数据库关系模式、分片规则等复杂问题,同时你还需要处理因数据库分片导致的跨分片事务问题。 这时,你不得不修改你的业务代码,以适应水平拆分后的数据库架构。
然而,如果你选择使用 Wow 框架,你将不再需要过多关注数据库关系模式、分片规则等问题。你的业务代码无需变更,系统能够轻松实现水平伸缩。
你可以在这里了解更多关于 Wow 框架的性能。
读写分离与同步延迟
读写分离是一种极为普遍的性能优化架构模式。 然而,同步延迟问题常伴随而来,事务执行成功后写库落库成功,但读库同步延迟,用户刷新页面后无法获取最新数据,从而对用户的体验产生影响。例如:
- 用户发起下单事务,写库执行成功,但由于某种原因,读库同步延迟,用户刷新页面后发现订单未成功创建。
- 商家编辑完商品后,同步到 Elasticsearch 索引库,但由于某种原因,同步延迟,导致商家刷新页面后搜索不到该商品。
通常,大家采用最简便的方法,等待 1 秒后刷新页面。 虽然这种方式能解决大多数数据同步延迟的问题,但效率不够高。 因为大多数情况下,同步在 100 毫秒内就已完成,剩余的 900 毫秒成了浪费。 然而,有时 1 秒无法完成同步,这就导致用户获取的数据变得无效。
使用 Wow 框架,你可以通过等待 PROJECTED 信号完成,然后再将结果返回给用户,以更为优雅和高效的方式处理数据同步延迟的问题。
工程质量
单元测试是确保代码质量且符合预期业务需求的重要手段,但在传统架构中,单元测试往往是一项相当困难的任务,因为你需要考虑数据库连接、事务管理、数据清理等问题。
使用 Wow 框架,你将会发现基于 Given->When->Expect 模式的测试套件,使得单元测试变得异常简单。 你只需关注领域模型是否符合预期,而无需为数据库连接等问题烦恼。
在实际应用中,我们将领域模型的单元测试覆盖率下限阈值设置为 85%,也是可以轻松实现的。
在没有刻意要求的情况下,开发人员甚至自觉地将覆盖率提升至 95%。
因此,每次提交代码都变得轻松自在,因为你确信你的代码经过了充分的测试,并且真正意义上从单元测试中获得了收益。
在研发同级别的项目中,我们的测试团队在系统 API 测试中发现,基于 Wow 框架的项目,其 BUG 数仅为传统架构项目的 1/3。
你可以在这里了解更多关于 Wow 单元测试套件。
对于企业而言,Wow 框架意味着什么?
商业智能
商业智能是企业决策的关键支持,而数据则是商业智能的分析原料。业务数据越为丰富有价值,商业智能的分析结果越准确,决策也就更加可靠。
与传统架构有着显著差异,Wow 提供了实时聚合根状态事件(StateEvent
)和聚合命令(Command
)作为数据分析的数据源,同时极大降低了实时 ETL(Extract
, Transform
, Load
)的难度。
在传统架构中,实现实时 ETL 通常需要经过繁琐的流程,包括 DB->CDC->Process->DB
,而在 Wow 框架中,仅需一段简单的 SQL 脚本即可完成这一过程。
另外,在传统架构中,使用 CDC(MySql Binlog
)数据仅记录数据的变化,缺乏明确的业务语义。进行业务分析时,需要基于数据状态的变化推断出业务语义,这往往需要进行大量的数据处理。 相较之下,Wow 框架直接提供了聚合根状态事件和聚合命令作为数据分析的数据源,极大降低了数据处理的难度。
Wow 提供的实时同步机制将数据实时同步至数据仓库(ClickHouse),为实时数据分析提供了极大的便利。这种方法为商业智能提供了强有力的支持,构建了一个实时数据分析系统,使决策制定能够基于及时而准确的信息。
你可以在这里了解更多关于 Wow 商业智能。
操作审计
操作审计是企业中保障安全性和合规性的重要组成部分,同时也是对系统操作进行监控和追踪的关键手段。Wow 框架在这方面为企业带来了显著的优势。
通过记录聚合命令(Command
)作为操作审计的数据源,Wow 框架能够详细追踪系统中的各种操作。 这些记录不仅包含了操作本身的内容,还涵盖了操作触发的副作用(领域事件),为审计提供了更为全面和准确的数据基础。
相较于传统审计方法,Wow 框架的操作审计的数据源具备更加明确的业务语义,以及操作后产生的明确领域事件。
此外,Wow 框架提供的实时数据同步机制也为操作审计带来了便利,确保了审计数据的及时性和一致性。
了解更多关于 Wow 操作审计。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
FolkMQ 增加 Node.js 客户端,v1.3.1 发布
FolkMQ,作一个最简单的消息中间件(单机版,约 180K TPS)。面向简单,面向未来! 功能简介 角色 功能 生产端(或发起端) 发布消息、定时消息(或叫延时)、顺序消息、可过期消息、事务消息。发送消息(rpc) 支持 Qos0、Qos1 消费端(或接收端) 订阅、取消订阅。消费-ACK(自动、手动)。监听(rpc) 服务端 发布-Confirm、订阅-Confirm、取消订阅-Confirm、派发-Retry、派发-Delayed 服务端 单线程、内存运行、快照持久化(自动、停机、手动)、Broker 模式集群、集群热扩展 中间件特点 高吞吐量、低延迟 集群模式每秒能处理百万消息,最低延迟不到1毫秒。 可扩展性 集群模式支持服务节点热扩展。流量高时随时加,流量低时可减。视频: 《FolkMQ - "多中心" 集群模式部署视频》 持久性、可靠性 消息被快照持久化(类似于 redis)到本地磁盘,并且支持数据备份防止数据丢失 可集群、高可用 可单机,可集群。集群内任何节点坏掉只要还有“一个”同类节点,仍可提供服务。视频: 《FolkMQ - 集群"高可用性"测试视频》 本次...
- 下一篇
【比较 ORM 操作数据】总结
写在最后 经过将近一周时间的框架收集、学习、实验、编码、测试市面上常见的ORM框架,过程中拜读了很多作者的博文、样例,学习很多收获很多。 重新梳理下整理的框架:mybatis-plus、lazy、sqltoy、mybatis-flex、easy-query、mybatis-mp、jpa、dbvisitor、beetlsql 下面从一下几点出发作出总结 文档方面:学习过程中mybatis-plus、jpa 提供的文档资料是比较全和晚上,经得住市场的考验 技术方面:beetlsql、easy-query、mybatis系列 三类框架都已经支持spring 和solon生态 其技术架构设计可以推荐大家学习 并发方面:jpa、db_visitor 还需要开发时候深度优化处理 大数据存储方面: Lazy 具有一定优势 大数据查询方面:sqltoy反射处理的比较优秀 以上是个人整理的观点,如果大家有不同的想法和意见可以在gitee或者个人博客留言CSDN 细节数据对比(一万以内基本相差不大) 细节数据对比,数据属于并发行测试数据,如果测试总数是一百,那么会执行一百次batchStory,一百次fi...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题