Page 1 of 1

所描述的解决方案不会回滚业务

Posted: Thu Jan 30, 2025 9:39 am
by suchona.kani.z
与两阶段提交相比,如果发送集成事件失败,逻辑。在许多情况下,这并不是一个缺点 - 例如,如果价格变化或订单在延迟后报告给计费服务,这通常是可以接受的,或者比仅仅因为计费服务而必须拒绝订单更好目前不可用。

Spring Data JPA 和应用程序事件中的实现
我们现在希望基于 Spring 应用程序事件和 Data JPA 在 Java 中实现上述方法。我们假设使用经典的关系数据库,并且集成事件应通过 HTTP POST 请求发送。

基础:春季的应用程序事件
Spring 提供了一个可以发布任何对象ApplicationEventPublisher的接口。publishEvent然后可以在 Spring 应用程序中以各种方式响应此类事件。

最简单的选项是注释@EventListener,它允许将方法注册为事件侦 贷款人员电子邮件列表 听器。方法的签名,或更准确地说是其参数的类型,声明事件侦听器注册哪些事件。默认情况下,以这种方式注释的事件监听器是同步调用的,这意味着发布事件的服务只有在所有监听器都处理完毕后才继续运行。

注释@TransactionalEventListener允许更多控制:在这里,事件的处理可以放置在事务的上下文中,并且侦听器的调用可以绑定到事务的特定阶段。例如@TransactionalEventListener(phase=TransactionPhase.AFTER_COMMIT),指定侦听器仅应在成功提交后调用。或者,执行也可以在阶段BEFORE_COMMIT和中进行AFTER_ROLLBACK。

顺便说一句,Spring 本身在内部使用这些机制;例如,ApplicationContext 发布框架事件ContextStartedEvent和ContextRefreshedEvent.

解决方案概述
我们的实现利用了上述 Spring 的功能,如下所示:

专家模块通过 ApplicationEventPublisher 发送集成事件以及有关价格变化的相关信息。这发生在通过 JPA 保存价格变化的交易中。
处理集成事件的模块(以下简称集成事件服务)@EventListener使用 来监听事件。它将序列化并通过 JPA 将其保存在保存技术数据(在示例中为价格)的同一数据库中。由于它@EventListener是同步工作的,因此这发生在同一个事务中。
- 仅在成功提交价格更改(和事件)后,事件才会从集成事件服务发送到其他服务。这是由 触发的@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)。


在技​​术模块中发布集成事件
根据架构风格,业务模块中的事件可以通过服务、DDD 实体或其他构造来发送,但基本过程是相同的。为了简单起见,下面假设有一个服务。发布集成事件非常容易实现:它们ApplicationEventPublisher通过依赖项注入提供,发布集成事件只需调用publishEvent().以下代码在我们的价格更改示例中展示了这一点:


为了简单起见,在此代码示例中,有效负载(即集成事件的内容)仅由字符串组成。在生产应用中肯定需要更复杂的结构。顺便说一句,使用此解决方案,业务服务不依赖于 IntegrationEventService - 业务模块只需要知道发布者和 IntegrationEvent。