Отправка событий домена Spring с использованием пользовательского ApplicationEventPublisher

#java #spring #spring-data-jpa #event-driven-design #domain-events

#java #spring #spring-data-jpa #дизайн, управляемый событиями #домен-события

Вопрос:

Я пытаюсь реализовать приложение с использованием данных Spring Boot / Spring, следуя рекомендациям по архитектуре DDD. У меня есть совокупный корень, который публикует события домена с использованием метода AbstractAggregateRoot::registerEvent() . Кроме того, мне нужно перехватывать эти события для целей регистрации / отслеживания, поэтому я решил провести эксперимент:

Сначала внедрите пользовательский издатель ApplicationEvent

 public class CustomEventPublisher implements ApplicationEventPublisher {
    private final ApplicationEventPublisher publisher;

    private final Logger logger = getLogger(CustomEventPublisher.class);

    public CustomEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public void publishEvent(ApplicationEvent event) {
        logger.info("sending an event...");
        publisher.publishEvent(event);
    }

    //.....
}
  

А затем регистрация в качестве компонента

 @Configuration
public class CustomEventPublisherConfig {

    @Bean
    @Primary
    public ApplicationEventPublisher getCustomEventPublisher(ApplicationEventPublisher publisher , RabbitTemplate rabbitTemplate) {
        return new CustomEventPublisher(publisher, rabbitTemplate);
    }
}
  

это работает нормально, как только я явно публикую события из некоторого образца объекта с помощью введенного ApplicationEventPublisher

 public void pub() {
    publisher.publishEvent(new Event(this , 1));
}

@EventListener
public void sub(Event e) {
    this.value = e.getValue();
}
  

и я получил запись в журнале «отправка события …»

затем я попытался определить совокупный корень

 @Entity
public class AggregateRoot extends AbstractAggregateRoot {

    @Id
    @GeneratedValue
    private Long id;

    private int value = 0;

    public AggregateRoot setValue(int value) {
        registerEvent(new Event(this , value));
        return this;
    }
}
  

и

 public void pub() {
    repository.save(new AggregateRoot().setValue(1));
}
  

Повторите тест, но я ясно вижу, что Spring Data не использует CustomEventPublisher. Я попытался понять, есть ли какой-то способ перехватить вызов repository.save() и переопределить поведение по умолчанию, этот подход может сработать, даже если потребуется изобретать велосипед (я не думаю, что код публикации событий домена настолько сложен), но единственное, что я нашел, это примерноОстаток данных Spring, который выходит за рамки моей области

Есть предложения по преодолению этой проблемы?

Заранее спасибо

Комментарии:

1. Можете ли вы объяснить registerEvent(new Event(this , value)); в AggregateRoot

2. @GSSwain docs.spring.io/spring-data/commons/docs/current/api/org/…

Ответ №1:

Насколько я знаю, Spring не предоставляет способа заменить издателя, используемого EventPublishingRepositoryProxyPostProcessor . И мне кажется, что вы выбрали не совсем правильный путь, чтобы получить то, чего вы хотите достичь, поэтому я отвечаю не на ваш прямой вопрос, а на ваши требования, описанные в начале.

Я бы посоветовал вам зарегистрировать прослушиватель с помощью @EventListener и обработать ваше событие там:

 @EventListener
public void handleEvent(Event event) {
    System.out.println(event);
}
  

Или вы можете использовать @TransactionalEventListener для привязки прослушивателя к фазе транзакции:

 @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleEvent(Event event) {
    System.out.println(event);
}
  

Комментарии:

1. Хорошо, это то, что я обнаружил до сих пор. Кроме того, TransactionalEventListener не является необходимым для эксперимента