簡體   English   中英

如何使用 spring 正確發布 DDD 域事件?

[英]How to properly publish DDD domain events with spring?

我正在嘗試在我的項目中實現領域驅動設計。 這是我的基本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不能自動@Component ,因為UUIDAggregate不是Autowired@Bean 一種解決方案是創建DomainService並在那里發布事件,但這似乎是將域泄漏到域服務,如果我 go 那樣,我會貧血 model。 另外,我可以做的是將DomainEventPublisher作為參數傳遞給每個聚合,但這似乎也不是一個好主意。

一個想法是為域對象建立一個工廠:

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

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

那么您創建域 object 的代碼是“無發布者”:

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

這與您的建議不同:服務發布事件,但不創建事件 - 邏輯保留在域 object 中。

此外,您可以更改發布者以最小化樣板代碼:

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

Vaughn Vernon 在他的《IDDD》一書中只使用了 singleton,如下所示:

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

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

我知道這種方法不使用 spring 注入,但它比將發布者傳遞給每個聚合要簡單得多,而且測試起來也不難。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM