- 如何将领域事件建模成对象,何时应该为领域事件创建唯一的身份标识?
- 哪些组件用于发布事件,哪些组件用于订阅事件
- 为什么我们需要一个事件存储?如何实现事件存储、如何使用事件存储?
- 如何通过不同的方式将领域事件发布给自治系统
1 when and why使用领域事件?
1.1 定义
使用领域事件时,首先就是要对不同事件进行定义。
《领域驱动设计》并未给出领域事件的定义,因为该模型是在该书出版后才被提出。
当前对领域事件的定义:领域专家所关心的发生在领域中的一些事件。将领域中所发生的活动建模成一系列的离散事件。
每个事件都用领域对象来表示,领域事件是领域模型的组成部分,表示领域中所发生的事情。
如何确定哪些事件对领域专家重要?
1.2 识别领域事件
- “当……”
- “如果发生……,则……”
- “当做完……的时候,请通知……”
- 这里的通知本身并不构成一个事件,只是表明我们需要向外界发出通知.
在这些场景中,若发生某种事件后,会触发进一步操作,则该事件很可能就是领域事件。
有时从领域专家话中,好像也还看不出哪里有领域事件,但业务需求依然可能需要领域事件。领域专家有时可能意识不到这些需求,只有在经过跨团队讨论后才意识到这些。
之所以会这样,是由于领域事件需发布到外部系统,如到另一个限界上下文。由于这样的事件由订阅方处理,它将对本地和远程上下文都产生影响。
由于领域事件需要发布到外部系统,如发布到另一个限界上下文。这样的事件由订阅方处理,影响本地和远程上下文。
一个领域事件将导致进一步业务操作,在实现业务解耦同时,还有助于形成完整的业务闭环。
领域事件可以是业务流程的一个步骤,如一个事件发生后触发的后续动作:密码连续输错三次,触发锁定账户的动作。
领域事件为何要用最终一致性,而非SOA直接调用?
因为聚合的一个原则:一个事务中最多只能更改一个聚合实例,所以:
- 本地限界上下文中的其他聚合实例,可通过领域事件的方式同步
- 用于使远程依赖系统与本地系统保持一致
解耦本地系统和远程系,有助提高双方协作服务的可伸缩性
聚合创建并发布事件
- 订阅方可先存储事件,然后再将其转发到远程订阅方
- 或不经存储,直接转发
除非MQ共享了模型的数据存储,不然即时转发需要XA(两阶段提交)。 - 系统业务低峰期,批处理过程通常进行一些系统维护工作,如删除过期对象、创建新对象以支持新业务需求或通知用户所发生的重要事件。
这样的批处理过程通常需复杂查询&&庞大事务。若这些批处理过程存在冗余会怎样?
系统中发生的每一件事情,都用事件形式捕获,然后将事件发布给订阅方处理,能简化系统吗?
肯定的!它可消除先前批处理过程中的复杂查询,因为我们能够准确知道在何时发生何事,限界上下文也由此知道接下来应该做啥。在接收到领域事件时,系统可立即处理。原本批量集中处理的过程可以分散成许多粒度较小的处理单元,业务需求也由此更快满足,用户也可及时进行下一步操作。
领域事件驱动设计可切断领域模型之间的强依赖。
事件发布完成后,发布方不必关心后续订阅方事件处理是否成功,即可实现领域模型的解耦,维护领域模型的独立性和数据一致性。
在领域模型映射到微服务架构时,领域事件可解耦微服务,微服务间的数据不必要求强一致性,而是基于事件的最终一致性。