春季如何正确发布DDD域事件? [英] How to properly publish DDD domain events with spring?

查看:114
本文介绍了春季如何正确发布DDD域事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to implement domain driven design in my project. Here is my base Aggregate class:

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 不能自动连线,因为 UUIDAggregate 不是 @Component @Bean 。一种解决方案是创建 DomainService 并在那里发布事件,但这似乎是域到域服务的泄漏,如果我这样做,我将使用贫血模型。我还能做的是将 DomainEventPublisher 作为参数传递给每个聚合,但这似乎也不是一个好主意。

Now, this seems like a good idea, the domain is separated from implementation but this does not work. DomainEventPublisher cannot be Autowired because UUIDAggregate is not a @Component or @Bean . One solution would be to create DomainService and publish event there but that seems like leaking of domain to domain service and if I go that way, I am going to anemic model. Also what I can do is to pass DomainEventPublisher as a parameter to every aggregate but that also does not seems like a good idea.

推荐答案

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

One idea would be to have a factory for domain objects:

@Component
class UserAccountFactoryImpl implements UserAccountFactory {
    @Autowired
    private DomainEventPublisher publisher;

    @Override
    public UserAccount newUserAccount(String email, String username, ...) {
        return new UserAccount(email, username, ..., publisher);
    }
}

然后,您创建域对象的代码是 publisher-免费:

Then your code creating a domain object is "publisher-free":

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

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

Or you might slightly change the design of the event-publishing:

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);
    }
}

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

This is different from your proposal: the service publishes the events, but doesn't create then - the logic stays in the domain object.

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

Further, you can change your publisher to minimize the boiler-plate code:

public interface DomainEventPublisher {
   void publish(UUIDAggregate aggregate);
}

这篇关于春季如何正确发布DDD域事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆