Может ли он зарегистрировать событие домена в конструкторе агрегатного корня при использовании Spring Data Common - PullRequest
0 голосов
/ 29 августа 2018

Агрегат будет создан некоторым application service, а не другим агрегатом.

Как это

SomeAggregate aggregate = new SomeAggregate();
repo.save(aggregate);

Ожидается, что aggregate будет сохранено и одно событие SomeAggregateCreated будет опубликовано после завершения работы службы приложения. Я проверил это, это не всегда эффективно, иногда событие не регистрируется сразу после выполнения конструктора.

Это класс учителя:

public class Teacher extends AbstractAggregateRoot<Teacher> {

    public Teacher() {
        registerEvent(new TeacherAdded(id, name));
    }
}

Это TeacherAdded:

@AllArgsConstructor
@Getter
@ToString
@EqualsAndHashCode(callSuper = true)
public class TeacherAdded extends AbstractDomainEvent {
    private TeacherId teacherId;    
    private String name;
}

Это AbstractDomainEvent и DomainEvent

@Getter
@ToString()
@EqualsAndHashCode()
public abstract class AbstractDomainEvent implements DomainEvent {
    protected Date occurredOn;

    public AbstractDomainEvent() {
        this(new Date());
    }

    public AbstractDomainEvent(Date occurredOn) {
        this.occurredOn = occurredOn != null ? occurredOn : new Date();
    }

    @Override
    public Date occurredOn() {
        return occurredOn;
    }    
}

public interface DomainEvent {
    public Date occurredOn();
}

AbstractAggregateRoot скопирован из org.springframework.data.domain.AbstractAggregateRoot<A>, а метод hasCapturedEvent добавлен для тестирования.

public boolean hasCapturedEvent(DomainEvent event) {
    return domainEvents.contains(event);
}

Если я запускаю это:

// ...
TeacherAdded teacherAdded = new TeacherAdded(teacherId, teacherName);
Teacher teacher = new Teacher();
assertTrue(teacher.hasCapturedEvent(teacherAdded)); 

Иногда это терпит неудачу, а иногда и успешно.

1 Ответ

0 голосов
/ 28 сентября 2018

Ответ yes. События домена, зарегистрированные конструктором, могут быть опубликованы и прослушаны в обычном режиме. Они совпадают с событиями, зарегистрированными обычным способом.

Тест, который я указал в описании проблемы, неисправен. После изменения AbstractDomainEvent.hasCapturedEvent и связанного с ним кода тест можно пройти.

Это новый AbstractDomainEvent.hasCapturedEvent и метод испытания.

    public boolean hasCapturedEvent(DomainEvent event, long occurredOnAdjustment) {
        if (occurredOnAdjustment <= 0) {
            return this.domainEvents.contains(event);
        } else {
            return this.domainEvents.stream().anyMatch(eventOnStream -> {
                return eventOnStream.equalsExcludedOccurTime(event)
                    && System.currentTimeMillis() - eventOnStream.occurredOn().getTime() <= occurredOnAdjustment;
            });
        }
    }

        TeacherAdded teacherAdded = new TeacherAdded(teacherId, teacherName);
        Teacher teacher = new Teacher();
        assertTrue(teacher.hasCapturedEvent(teacherAdded, 1000L)); 

Это новый TeacherAdded.

public interface DomainEvent {
    public Date occurredOn();

    public default boolean equalsExcludedOccurTime(DomainEvent other) {
        return false;
    }
}

@lombok...
public class TeacherAdded extends AbstractDomainEvent {
    private TeacherId teacherId;    
    private String name;

    @Override
    public boolean equalsExcludedOccurTime(DomainEvent other) {
        if (!(other instanceof TeacherAdded)) {
            return false;
        } else {
            TeacherAdded other2 = (TeacherAdded)other;
            return Objects.equals(teacherId, other2.teacherId)
                && Objects.equals(name, other2.name);
        }
    }
}
...