为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

达令说 2023-09-27 10:11:49
我正在尝试在我的项目中实现领域驱动设计。这是我的基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:@Componentpublic class DomainEventPublisherImpl implements DomainEventPublisher{    @Autowired    private ApplicationEventPublisher publisher;    public void publish(DomainEvent event){        publisher.publishEvent(event);    }}现在,这似乎是一个好主意,域与实现分离,但这不起作用。DomainEventPublisher不能是,Autowired因为UUIDAggregate不是@Component或@Bean。一种解决方案是DomainService在那里创建和发布事件,但这似乎会将域泄漏到域服务,如果我这样做,我将陷入贫血模型。另外,我能做的就是DomainEventPublisher作为参数传递给每个聚合,但这似乎也不是一个好主意。
查看完整描述

2 回答

?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

一个想法是为域对象建立一个工厂:


@Component

class UserAccountFactoryImpl implements UserAccountFactory {

    @Autowired

    private DomainEventPublisher publisher;


    @Override

    public UserAccount newUserAccount(String email, String username, ...) {

        return new UserAccount(email, username, ..., publisher);

    }

}

那么创建域对象的代码是“无发布者的”:


UserAccount userAccount = factory.newUserAccount("john@example.com", ...);

或者您可以稍微更改事件发布的设计:


public abstract class UUIDAggregate {

    private final List<DomainEvent> domainEvents = new ArrayList<>();


    protected void publish(DomainEvent domainEvent) {

        domainEvents.add(domainEvent);

    }

    public List<DomainEvent> domainEvents() {

        return Collections.unmodifiableList(domainEvents);

    }

}


@Component

class UserAccountServiceImpl implements UserAccountService {

    @Autowired

    private DomainEventPublisher publisher;


    @Override

    public void updateUserAccount(UserAccount userAccount) {

        userAccount.update();


        userAccount.domainEvents().forEach(publisher::publishEvent);

    }

}

这与您的建议不同:服务发布事件,但不创建事件 - 逻辑保留在域对象中。


此外,您可以更改发布者以最小化样板代码:


public interface DomainEventPublisher {

   void publish(UUIDAggregate aggregate);

}


查看完整回答
反对 回复 2023-09-27
?
三国纷争

TA贡献1804条经验 获得超7个赞

Vaughn Vernon 在他的《IDDD》一书中就这样使用了单例:

DomainEventPublisher.instance().register(...);

DomainEventPublisher.instance().publish(...);

我知道这种方法不使用弹簧注入,但它比将发布者传递给每个聚合要简单得多,而且测试起来也不难。


查看完整回答
反对 回复 2023-09-27
  • 2 回答
  • 0 关注
  • 96 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信