使用自定义ApplicationEventPublisher发送Spring域事件

问题描述

我正在尝试根据DDD体系结构准则使用Spring Boot / Spring Data实现应用程序。我有一个聚合根,它使用 AbstractAggregateRoot :: registerEvent()方法发布域事件。此外,出于日志记录/跟踪的目的,我需要拦截这些事件,因此我决定进行实验:

首先,实现自定义ApplicationEvent Publisher

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

    //.....
}

然后注册为bean

@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 Data REST的问题,

有什么建议可以解决这个问题?

预先感谢

解决方法

据我所知,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);
}