如果事件是从另一个侦听器发布的,则忽略 TransactionalEventListener

TransactionalEventListener ignored if event is published from another listener

我有一个服务和两个阶段为 BEFORE_COMMIT 的 TransactionalEventListener,一个监听 EventA,另一个监听 EventB。服务发布 EventA -> EventAListener 被调用并发布另一个事件 - EventB。 EventBListener 未被调用,事件被忽略。 示例代码:

@Service
@Transactional
public class ExampleService {
    private ExampleEntityRepository repository;
    private ApplicationEventPublisher applicationEventPublisher;

    public void exampleMethod() {
        repository.save(new ExampleEntity("entity"));
        applicationEventPublisher.publishEvent(new EventA(this));
    }
}

//==================================================

@Service
@Transactional
public class EventAListener {
    private ExampleEntityRepository repository;
    private ApplicationEventPublisher applicationEventPublisher;

    @TransactionalEventListener(value = EventA.class, phase = TransactionPhase.BEFORE_COMMIT)
    public void handle(EventA event) {
        repository.save(new ExampleEntity("entityA"));
        applicationEventPublisher.publishEvent(new EventB(this));
    }
}

//==================================================

@Service
@Transactional
public class EventBListener {
    private ExampleEntityRepository repository;

    @TransactionalEventListener(value = EventB.class, phase = TransactionPhase.BEFORE_COMMIT)
    public void handle(EventB eventB) {
        repository.save(new ExampleEntity("entityB"));
    }
}

//==================================================

// Alternative EventAListener version
@Service
@Transactional
public class EventAListener {
    private ExampleEntityRepository repository;

    @TransactionalEventListener(value = EventA.class, phase = TransactionPhase.BEFORE_COMMIT)
    public EventB handle(EventA event) {
        repository.save(new ExampleEntity("entityA"));
        return new EventB(this);
    }
}

执行服务方法后,数据库中有 2 行 - "entity" 和 "entityA"。
替代 EventAListener 版本的工作方式相同。
将 EventBListener fallbackExecution 设置为 'true' 不会进行任何更改 - 不会调用 EventBListener。
将 EventBListener 阶段更改为 AFTER_COMMIT 有效 - EventB 已处理,但在另一个事务中。

为什么 EventB 没有被处理?

我认为您的问题可能与 Wojtek 在此处发布的问题有关: https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2

Spring 开发者回答如下:

BEFORE_COMMIT is not "anytime you want during the transaction". It's really before commit. What you're doing is using the transaction like nothing asked for a commit. Something did.

因此,BEFORE_COMMIT 事件的链接似乎是不可能的,也许不支持在该阶段执行另一个事务操作(即使它看起来有效)?

我认为这个领域可以更好地记录下来,因为对大多数人来说 "before commit" 只是意味着 "before something was committed",并不清楚当调用该事件处理程序时可以执行哪些操作。