【问题标题】:DDD: Where to raise "created" domain eventDDD:在哪里引发“创建”域事件
【发布时间】:2020-11-05 22:27:51
【问题描述】:

我很难找到并实施以下问题的最佳实践:引发create域事件(通知创建聚合的事件)的最佳位置在哪里。例如,如果我们在有界上下文中有 订单聚合,我们希望在创建订单时通知所有相关方。该事件可能是 OrderCreatedEvent

我首先尝试的是在构造函数中引发此事件(我在每个聚合中都有一个域事件集合)。这样只有在我们创建订单时才可以。因为当我们将来想对这个聚合做任何事情时,我们将通过构造函数创建它的新实例。然后 OrderCreatedEvent 将再次引发,但它不是真的。

但是,我认为在应用层引发事件是可以的,但这是一种反模式(域事件应该只存在于域中)。也许有一个方法 Create 只会将 OrderCreatedEvent 添加到其域事件列表中,并在创建订单时在应用程序层调用它是一种选择。

我在互联网上发现的有趣事实是,在构造函数中引发域事件是一种反模式,这意味着最后描述的选项(具有 Create 方法)将是最好的方法。

我将 Spring Boot 用于应用程序,将 MapStruct 用于将 数据库/存储库实体 映射到域模型聚合的映射器。此外,试图找到一种方法来创建一个映射器,该映射器将跳过目标类的构造函数,但由于 Order 聚合的所有属性都是私有的,这似乎是不可能的。

【问题讨论】:

    标签: spring-boot domain-driven-design mapstruct


    【解决方案1】:

    通常构造函数仅用于对对象的字段进行赋值。这不是触发行为的正确位置,尤其是当它们抛出异常或有副作用时

    DDD 理论家(从 Eric Evans 开始)建议实施工厂来创建聚合。例如,工厂方法可以调用聚合构造函数(并将聚合与子域对象连接起来)并注册一个事件。

    从应用层发布事件本身并不是一种反模式。应用服务可以依赖于领域事件发布者,重要的是它不是应用层来决定发送哪个事件

    总而言之,借助 Java Spring Boot 之类的堆栈和域事件支持,您的代码可能看起来像

    public class MyAggregate extends AbstractAggregateRoot {
        public static MyAggregate create() {
            MyAggregate created = new MyAggregate();
            created.registerEvent(new MyAggregateCreated());
            return created;
        }
    }
    
    public class MyApplicationService {
        @Autowired private MyAggregateRepository repository;
    
        public void createAnAggregate() {
            repository.save(MyAggregate.create());
        }
    }
    

    请注意,在调用 repository.save() 之后,事件发布会自动发生。这里的缺点是,当您使用 db 生成的标识符时,聚合 id 在事件有效负载中不可用,因为它是在持久化聚合后关联的。如果我会像这样更改应用程序服务代码:

    public class MyApplicationService {
        @Autowired private MyAggregateRepository repository;
        @Autowired private ApplicationEventPublisher publisher;
    
    
        public void createAnAggregate() {
            repository.save(MyAggregate.create()).domainEvents().forEach(evt -> {
                publisher.publish(evt);
            });
        }
    }
    

    应用层负责决定如何完成这个工作流程(创建一个聚合、持久化并发送一些事件),但所有步骤都是透明地发生的。我可以将新属性添加到聚合根、更改 DBMS 或更改事件合同,这不会更改这些代码行。应用层决定做什么,领域层决定怎么做。工厂是领域层的一部分,事件是聚合状态的瞬态部分,而发布部分从领域的角度来看是透明的

    【讨论】:

      【解决方案2】:

      看看这个问题! Is it safe to publish Domain Event before persisting the Aggregate?。 但是,我认为在应用程序层中引发事件是可以的,但它是一种反模式(域事件应该只存在于域中)。 - 领域事件存在于领域层,但应用层引用领域层,可以轻松发出领域事件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-27
        • 2017-01-29
        • 1970-01-01
        • 2010-10-16
        相关资源
        最近更新 更多