如何用spring正确发布DDD领域事件?

我正在尝试在我的项目中实现领域驱动设计。这是我的基Aggregate类:


public abstract class UUIDAggregate {

    private final DomainEventPublisher domainEventPublisher;


    protected void publish(DomainEvent domainEvent) {

        domainEventPublisher.publish(domainEvent);

    }

}

假设我们有UserAccount聚合:


public class UserAccount extends UUIDAggregate {

    private String email;

    private String username;

    private String password;

    private String firstName;

    private String lastName;


    public void update() {

        publish(new DomainEventImpl());

    }

}

这是我的DomainEventPublisher:


public interface DomainEventPublisher {

   void publish(DomainEvent event);

}

这是DomainEventPublisherImpl:


@Component

public class DomainEventPublisherImpl implements DomainEventPublisher{

    @Autowired

    private ApplicationEventPublisher publisher;


    public void publish(DomainEvent event){

        publisher.publishEvent(event);

    }

}

现在,这似乎是一个好主意,域与实现分离,但这不起作用。DomainEventPublisher不能是,Autowired因为UUIDAggregate不是@Component或@Bean。一种解决方案是DomainService在那里创建和发布事件,但这似乎会将域泄漏到域服务,如果我这样做,我将陷入贫血模型。另外,我能做的就是DomainEventPublisher作为参数传递给每个聚合,但这似乎也不是一个好主意。


达令说
浏览 97回答 2
2回答

Smart猫小萌

一个想法是为域对象建立一个工厂:@Componentclass UserAccountFactoryImpl implements UserAccountFactory {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private DomainEventPublisher publisher;&nbsp; &nbsp; @Override&nbsp; &nbsp; public UserAccount newUserAccount(String email, String username, ...) {&nbsp; &nbsp; &nbsp; &nbsp; return new UserAccount(email, username, ..., publisher);&nbsp; &nbsp; }}那么创建域对象的代码是“无发布者的”:UserAccount userAccount = factory.newUserAccount("john@example.com", ...);或者您可以稍微更改事件发布的设计:public abstract class UUIDAggregate {&nbsp; &nbsp; private final List<DomainEvent> domainEvents = new ArrayList<>();&nbsp; &nbsp; protected void publish(DomainEvent domainEvent) {&nbsp; &nbsp; &nbsp; &nbsp; domainEvents.add(domainEvent);&nbsp; &nbsp; }&nbsp; &nbsp; public List<DomainEvent> domainEvents() {&nbsp; &nbsp; &nbsp; &nbsp; return Collections.unmodifiableList(domainEvents);&nbsp; &nbsp; }}@Componentclass UserAccountServiceImpl implements UserAccountService {&nbsp; &nbsp; @Autowired&nbsp; &nbsp; private DomainEventPublisher publisher;&nbsp; &nbsp; @Override&nbsp; &nbsp; public void updateUserAccount(UserAccount userAccount) {&nbsp; &nbsp; &nbsp; &nbsp; userAccount.update();&nbsp; &nbsp; &nbsp; &nbsp; userAccount.domainEvents().forEach(publisher::publishEvent);&nbsp; &nbsp; }}这与您的建议不同:服务发布事件,但不创建事件 - 逻辑保留在域对象中。此外,您可以更改发布者以最小化样板代码:public interface DomainEventPublisher {&nbsp; &nbsp;void publish(UUIDAggregate aggregate);}

三国纷争

Vaughn Vernon 在他的《IDDD》一书中就这样使用了单例:DomainEventPublisher.instance().register(...); DomainEventPublisher.instance().publish(...);我知道这种方法不使用弹簧注入,但它比将发布者传递给每个聚合要简单得多,而且测试起来也不难。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java