Explicit notes on transaction phase processing

Issue: SPR-15323
This commit is contained in:
Juergen Hoeller 2017-03-07 13:50:01 +01:00
parent 9aaed2bcef
commit 8b741508a6
3 changed files with 36 additions and 28 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -98,6 +98,11 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM
this.phase = phase; this.phase = phase;
} }
@Override
public int getOrder() {
return this.listener.getOrder();
}
@Override @Override
public void beforeCommit(boolean readOnly) { public void beforeCommit(boolean readOnly) {
if (this.phase == TransactionPhase.BEFORE_COMMIT) { if (this.phase == TransactionPhase.BEFORE_COMMIT) {
@ -107,20 +112,15 @@ class ApplicationListenerMethodTransactionalAdapter extends ApplicationListenerM
@Override @Override
public void afterCompletion(int status) { public void afterCompletion(int status) {
if (this.phase == TransactionPhase.AFTER_COMPLETION) { if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {
processEvent();
}
else if (this.phase == TransactionPhase.AFTER_COMMIT && status == STATUS_COMMITTED) {
processEvent(); processEvent();
} }
else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) { else if (this.phase == TransactionPhase.AFTER_ROLLBACK && status == STATUS_ROLLED_BACK) {
processEvent(); processEvent();
} }
} else if (this.phase == TransactionPhase.AFTER_COMPLETION) {
processEvent();
@Override }
public int getOrder() {
return this.listener.getOrder();
} }
protected void processEvent() { protected void processEvent() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,6 +22,7 @@ import org.springframework.transaction.support.TransactionSynchronization;
* The phase at which a transactional event listener applies. * The phase at which a transactional event listener applies.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Juergen Hoeller
* @since 4.2 * @since 4.2
* @see TransactionalEventListener * @see TransactionalEventListener
*/ */
@ -33,17 +34,11 @@ public enum TransactionPhase {
*/ */
BEFORE_COMMIT, BEFORE_COMMIT,
/**
* Fire the event after the transaction has completed. For
* more fine-grained event, use {@link #AFTER_COMMIT} or
* {@link #AFTER_ROLLBACK} to intercept transaction commit
* or rollback respectively.
* @see TransactionSynchronization#afterCompletion(int)
*/
AFTER_COMPLETION,
/** /**
* Fire the event after the commit has completed successfully. * Fire the event after the commit has completed successfully.
* <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and
* therefore executes in the same after-completion sequence of events,
* (and not in {@link TransactionSynchronization#afterCommit()}).
* @see TransactionSynchronization#afterCompletion(int) * @see TransactionSynchronization#afterCompletion(int)
* @see TransactionSynchronization#STATUS_COMMITTED * @see TransactionSynchronization#STATUS_COMMITTED
*/ */
@ -51,9 +46,20 @@ public enum TransactionPhase {
/** /**
* Fire the event if the transaction has rolled back. * Fire the event if the transaction has rolled back.
* <p>Note: This is a specialization of {@link #AFTER_COMPLETION} and
* therefore executes in the same after-completion sequence of events.
* @see TransactionSynchronization#afterCompletion(int) * @see TransactionSynchronization#afterCompletion(int)
* @see TransactionSynchronization#STATUS_ROLLED_BACK * @see TransactionSynchronization#STATUS_ROLLED_BACK
*/ */
AFTER_ROLLBACK AFTER_ROLLBACK,
/**
* Fire the event after the transaction has completed.
* <p>For more fine-grained events, use {@link #AFTER_COMMIT} or
* {@link #AFTER_ROLLBACK} to intercept transaction commit
* or rollback, respectively.
* @see TransactionSynchronization#afterCompletion(int)
*/
AFTER_COMPLETION
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2017 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,25 +28,27 @@ import org.springframework.core.annotation.AliasFor;
/** /**
* An {@link EventListener} that is invoked according to a {@link TransactionPhase}. * An {@link EventListener} that is invoked according to a {@link TransactionPhase}.
* *
* <p>If the event is not published within the boundaries of a managed transaction, the event * <p>If the event is not published within the boundaries of a managed transaction, the
* is discarded unless the {@link #fallbackExecution} flag is explicitly set. If a * event is discarded unless the {@link #fallbackExecution} flag is explicitly set. If a
* transaction is running, the event is processed according to its {@code TransactionPhase}. * transaction is running, the event is processed according to its {@code TransactionPhase}.
* *
* <p>Adding {@link org.springframework.core.annotation.Order @Order} on your annotated method * <p>Adding {@link org.springframework.core.annotation.Order @Order} to your annotated
* allows you to prioritize that listener amongst other listeners running in the same phase. * method allows you to prioritize that listener amongst other listeners running before
* or after transaction completion.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Sam Brannen * @author Sam Brannen
* @since 4.2 * @since 4.2
*/ */
@EventListener
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE}) @Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@EventListener
public @interface TransactionalEventListener { public @interface TransactionalEventListener {
/** /**
* Phase to bind the handling of an event to. * Phase to bind the handling of an event to.
* <p>The default phase is {@link TransactionPhase#AFTER_COMMIT}.
* <p>If no transaction is in progress, the event is not processed at * <p>If no transaction is in progress, the event is not processed at
* all unless {@link #fallbackExecution} has been enabled explicitly. * all unless {@link #fallbackExecution} has been enabled explicitly.
*/ */
@ -76,7 +78,7 @@ public @interface TransactionalEventListener {
/** /**
* Spring Expression Language (SpEL) attribute used for making the event * Spring Expression Language (SpEL) attribute used for making the event
* handling conditional. * handling conditional.
* <p>Default is {@code ""}, meaning the event is always handled. * <p>The default is {@code ""}, meaning the event is always handled.
* @see EventListener#condition * @see EventListener#condition
*/ */
String condition() default ""; String condition() default "";