Skip to content

@TransactionalEventListener does not work with SimpleApplicationEventMulticaster.setTaskExecutor #30244

Closed
@Basnucaev0

Description

@Basnucaev0

If the ApplicationEventMulticaster bean appears in the context, the @TransactionalEventListener annotation is useless, it will not work a priori and is not mentioned anywhere.

At the stage of this method, there is still a transaction in the publish event call chain, SimpleApplicationEventMulticaster.multicastEvent:

        @Override
	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
		Executor executor = getTaskExecutor();
		for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
			if (executor != null) {
				executor.execute(() -> invokeListener(listener, event));
			}
			else {
				invokeListener(listener, event);
			}
		}
	}

If we have an ApplicationEventMulticaster bean, then the first if will be executed and invokeListener will be executed deferred in a separate thread WHERE OUR TRANSACTION WILL NOT BE ALREADY.

Here's what's happening in invokeListener -> doInvokeListener -> TransactionalApplicationListenerMethodAdapter.onApplicationEvent():

	@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (TransactionSynchronizationManager.isSynchronizationActive() &&
				TransactionSynchronizationManager.isActualTransactionActive()) {
			TransactionSynchronizationManager.registerSynchronization(
					new TransactionalApplicationListenerSynchronization<>(event, this, this.callbacks));
		}
		else if (this.annotation.fallbackExecution()) {
			if (this.annotation.phase() == TransactionPhase.AFTER_ROLLBACK && logger.isWarnEnabled()) {
				logger.warn("Processing " + event + " as a fallback execution on AFTER_ROLLBACK phase");
			}
			processEvent(event);
		}
		else {
			// No transactional event execution at all
			if (logger.isDebugEnabled()) {
				logger.debug("No transaction is active - skipping " + event);
			}
		}
	}

When this code is executed asynchronously in a separate thread (executor), the transaction no longer exists.

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)in: dataIssues in data modules (jdbc, orm, oxm, tx)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions