[英]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.