本文上回书接《这是DDD建模最难的部分(其实很简单)》,欢迎关注我的同名公众号。
https://mp.weixin.qq.com/s/HZKMLF0_I10iczzp2mAR-w
 

故事背景

2013年中,我们的Java后端团队为了落地DDD,全面引入了dotnet技术栈,具体过程和成果,可以看我的B站频道《Java8 到 .NET8,团队升级报告 - 第二弹》https://www.bilibili.com/video/BV14YgYedE1f
 
在近半年的时间,我将自己落地DDD的实践经验进行提炼和总结,以公众号文章和B站视频的方式分享出来,与更多的网友建立链接和交流,得到了很多肯定反馈,也因为大家提供的视角,使得我自己对DDD的认知有了更深层次的迭代。
 
目前我们借助dotnet强大的生态以及csharp优良的语言设计,已经可以非常丝滑地用代码表达模型和业务,整个软件交付的体验和效率,获得了前所未有的进步。我们netcorepal-cloud-framework框架在这个过程中也得到了进化和可用性验证,我们坚信找到了一套更加务实的软件设计认知和方法论。
 

Javaer太难了

由于我们团队实际上还是Java和csharp双技术栈,于是我们萌生了一个想法,是否可以让我们的Java项目交付过程也如此地丝滑?带着这个想法,我们开始在Java生态中寻找可以帮助我们构建出类似csharp框架效果的组件:
 
  • Web框架: aspnetcore vs springboot
  • ORM:EntityFrameworkCore vs JPA
  • 中介者模式:MediatR vs ?
  • 事件的最终一致性实现:CAP vs ?
 
其中“中介者模式”和“事件的最终一致性”实现我们没有找到合适的替代品,经过分析,“中介者模式”并不是必须的,虽然最终实现起来,没有csharp那么优雅,但并不影响对建模设计的实现,但“事件的最终一致性”这个组件,我们认为是必不可少的,我们建模最底层的模型就是“命令-事件”模型,没有事件处理的健壮性,意味着最终系统的健壮性无法保障,最终无法满足业务对可用性的要求。
 

事件的最终一致性

 
在我们的建模模型中,是在命令处理逻辑中,由领域模型发出事件,而事件如果要在微服务间传递,我们期望达到的效果如下:
 
  1. 如果命令处理逻辑成功,即对应的数据库事务提交成功,则确保事件一定能够发出;
  2. 如果命令处理逻辑失败,即对应的数据库事务回滚,则确保事件一定不发出;
 
在需求层面,我们并不要求系统确保事件“确定只发一次”,我们知道,这个要求的技术实现难度远远大于前面的两个要求,而且业务可以做幂等处理解决重发的问题。
 
下图展示了我们csharp版本中关于“命令-事件”的建模实现,以及事务的具体实现:

 
在我们csharp的版本,我们使用了比较流行的CAP组件,https://github.com/dotnetcore/CAP,这个组件本质上是实现了outbox模式,通常也叫“发件箱模式”,借助这个组件,我们很轻易就实现了对于事件的最终一致性。
 
下图来自CAP组件的介绍页面,展示了发件箱模式的具体工作原理:
 
 
 
 
 
 
 
 
 
 
 
 
 
从原理上看,发件箱模式并不是一个复杂的能力,我们认为一向以生态好为优点的Java生态,也一定有类似且流行的组件,很不幸的是,我们在互联网以及能够触达的Java圈子里调研一番之后,得出了如下结论:
  1. Java生态有关于分布式事务的实现,例如:JEE,JBoss等,但目前基本没有团队在用了;
  2. Java生态没有现成的类似CAP这样的组件可以开箱即用;
 
上述结论仅表示我们目前的认知和信息渠道,如果有大佬能够给指个路,不甚感激!
 

cap4j

 
基于前面的结论,为了实现Java项目的DDD代码体验实践,我们开源了一个cap4j项目,期望能将CAP项目的能力移植到Java生态,项目地址:https://github.com/netcorepal/cap4j
该项目目前实现了JPA+RocketMQ的组合,我们规划在未来支持更多的ORM和MQ中间件,同时也会支持与CAP组件的协议兼容,以实现Java、dotnet异构架构的进一步融合。也欢迎大家为项目贡献代码和想法。
 

最后

 
关于技术生态这件事,可以说Java的生态好,但其它语言的生态我认为也都不差,在各自的领域都有非常多的优点。我在各个评论区,总是能看到各种不切实际的偏激言论,感受到种种的恶意。期望各个语言的技术栈从业者,能够更友好地交流,大家都是软件工程师,满足业务需求,实现商业价值,才是大家的更应该关注的。

为了给Javaer落地DDD,我们不得不写开源组件的更多相关文章

  1. freemarker写select组件(一)

    freemarker写select组件 1.宏定义 <#macro select id datas> <select id="${id}" name=" ...

  2. freemarker写select组件(五)

    freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...

  3. freemarker写select组件(四)

    freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...

  4. freemarker写select组件(三)

    freemarker写select组件 1.宏定义 <#macro select id datas value="" key="" text=" ...

  5. freemarker写select组件(二)

    freemarker写select组件 1.宏定义 <#macro select id datas value=""> <select id="${id ...

  6. django-admin 仿写stark组件action,filter筛选过滤,search查询

    写在StandLi里面的方法都是通过ModelSubject这个类里面的stand_li方法,在它里面用StandLi这个类实例化出来一个对象,这个实例化出来的对象把数据传给前端HTML模板进行渲染, ...

  7. vue-class-component 以class的模式写vue组件

    vue英文官网推荐了一个叫vue-class-component的包,可以以class的模式写vue组件.vue-class-component(以下简称Component)带来了很多便利: 1.me ...

  8. 使用docsify 写开源文档

    使用docsify 写开源文档 官网:https://docsify.js.org/#/ docsify 是一个动态生成文档网站的工具.不同于 GitBook.Hexo 的地方是它不会生成将 .md ...

  9. 手写开源ORM框架介绍

    手写开源ORM框架介绍 简介 前段时间利用空闲时间,参照mybatis的基本思路手写了一个ORM框架.一直没有时间去补充相应的文档,现在正好抽时间去整理下.通过思路历程和代码注释,一方面重温下知识,另 ...

  10. 手把手教你提交Jar包到Maven公共仓库 | 萌新写开源02

    在上一篇文章中,我介绍了自己的SpringBoot Starter项目,可以让我们使用注解的方式轻松地获取操作日志,并推送到指定数据源. 之前,我的项目开源在Github上,大家想要用我的项目,还得把 ...

随机推荐

  1. kylin-3.1.1-bin-hadoop3搭建,构建cube报的错误,Cannot modify dfs.replication at runtime. It is not in list of params that are allowed to be modified at runtime

    主要是每次构建cube时会去读取kylin安装目录下的conf/kylin_hive_conf.xml文件, 副本是无法在hive查询时修改的,注释掉这两项 这个其实还有一些参数的控制: 添加这俩个参 ...

  2. 制作Jdk镜像

    本文介绍用Dockerfile的方式构建Jdk镜像,请保证安装了Docker环境. 首先创建/opt/jdk目录,后续步骤都在该目录下进行操作. 准备好Jdk安装文件,放到/opt/jdk目录下. 编 ...

  3. python _XMLParser.__init__()初始化失败,提示“takes 1 positional argument but 4 were given”

    问题: 在一个新的环境下,执行openpyxl相关的操作,初始化时,逐步执行,需要调到 ElementTree.py _XMLParser.__init__(self, html, target, e ...

  4. mysql多表删除指定记录

    在Mysql4.0之后,mysql开始支持跨表delete. Mysql可以在一个sql语句中同时删除多表记录,也可以根据多个表之间的关系来删除某一个表中的记录. 假定我们有两张表:Product表和 ...

  5. 在WPF UWP WinUI中相同功能的用法的区别

    文件选择器 WPF:OpenFileDialog Microsoft.Win32.OpenFileDialog openFileDialog = new(); bool? result = openF ...

  6. ClickHouse介绍(三)MergeTree系列表引擎

    MergeTree系列表引擎 ClickHouse中最核心的引擎当属MergeTree系列引擎,其中基础表引擎为MergeTree,常用的表引擎还有ReplacingMergeTree.Summing ...

  7. 基于 Termux 和 ipv6 把手机打造成公网服务器

    Termux 安装与配置 安装 从这下载: https://f-droid.org/en/packages/com.termux/ 初始化 授权读写手机储存 termux-setup-storage ...

  8. 【论文阅读】RAL2022: Make it Dense: Self-Supervised Geometric Scan Completion of Sparse 3D LiDAR Scans in Large Outdoor Environments

    0. 参考与前言 论文链接:https://ieeexplore.ieee.org/document/9812507 代码链接:https://github.com/PRBonn/make_it_de ...

  9. 【价格全面下调】一片含税79元,双核A7@1.2GHz,-40℃~85℃真工业级!

    自9个月前,创龙科技全志T113-i核心板(SOM-TLT113)推出之后,受到广大工业用户的高度关注,且超过300家企业已选用创龙科技T113-i核心板用于终端产品开发. 为了让更多用户轻松选择T1 ...

  10. Blazor Server App Cannot find the fallback endpoint specified by route values

    github官方issues中提到的解决方案,CreateBuilder时指定项目绝对路径可以解决. 1 // 指定项目路径,也可以用Assembly.GetCallingAssembly获取 2 c ...