本文主要研究一下TransactionSynchronization的invokeAfterCompletion

afterCompletion

org/springframework/transaction/support/TransactionSynchronization.java

public interface TransactionSynchronization extends Flushable {

    /** Completion status in case of proper commit. */
    int STATUS_COMMITTED = 0;

    /** Completion status in case of proper rollback. */
    int STATUS_ROLLED_BACK = 1;

    /** Completion status in case of heuristic mixed completion or system errors. */
    int STATUS_UNKNOWN = 2;

    //......

    /**
     * Invoked after transaction commit. Can perform further operations right
     * <i>after</i> the main transaction has <i>successfully</i> committed.
     * <p>Can e.g. commit further operations that are supposed to follow on a successful
     * commit of the main transaction, like confirmation messages or emails.
     * <p><b>NOTE:</b> The transaction will have been committed already, but the
     * transactional resources might still be active and accessible. As a consequence,
     * any data access code triggered at this point will still "participate" in the
     * original transaction, allowing to perform some cleanup (with no commit following
     * anymore!), unless it explicitly declares that it needs to run in a separate
     * transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any
     * transactional operation that is called from here.</b>
     * @throws RuntimeException in case of errors; will be <b>propagated to the caller</b>
     * (note: do not throw TransactionException subclasses here!)
     */
    default void afterCommit() {
    }

    /**
     * Invoked after transaction commit/rollback.
     * Can perform resource cleanup <i>after</i> transaction completion.
     * <p><b>NOTE:</b> The transaction will have been committed or rolled back already,
     * but the transactional resources might still be active and accessible. As a
     * consequence, any data access code triggered at this point will still "participate"
     * in the original transaction, allowing to perform some cleanup (with no commit
     * following anymore!), unless it explicitly declares that it needs to run in a
     * separate transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW}
     * for any transactional operation that is called from here.</b>
     * @param status completion status according to the {@code STATUS_*} constants
     * @throws RuntimeException in case of errors; will be <b>logged but not propagated</b>
     * (note: do not throw TransactionException subclasses here!)
     * @see #STATUS_COMMITTED
     * @see #STATUS_ROLLED_BACK
     * @see #STATUS_UNKNOWN
     * @see #beforeCompletion
     */
    default void afterCompletion(int status) {
    }

}
afterCompletion方法有入参status,表示事务结束时候的状态,0表示事务已提交,1表示事务已回滚,2表示事务未知;与afterCommit的一个最重要的区别是afterCompletion的异常会被捕获,不像afterCommit会抛给调用方

invokeAfterCompletion

org/springframework/transaction/support/TransactionSynchronizationUtils.java

    /**
     * Actually invoke the {@code afterCompletion} methods of the
     * given Spring TransactionSynchronization objects.
     * @param synchronizations a List of TransactionSynchronization objects
     * @param completionStatus the completion status according to the
     * constants in the TransactionSynchronization interface
     * @see TransactionSynchronization#afterCompletion(int)
     * @see TransactionSynchronization#STATUS_COMMITTED
     * @see TransactionSynchronization#STATUS_ROLLED_BACK
     * @see TransactionSynchronization#STATUS_UNKNOWN
     */
    public static void invokeAfterCompletion(@Nullable List<TransactionSynchronization> synchronizations,
            int completionStatus) {

        if (synchronizations != null) {
            for (TransactionSynchronization synchronization : synchronizations) {
                try {
                    synchronization.afterCompletion(completionStatus);
                }
                catch (Throwable tsex) {
                    logger.error("TransactionSynchronization.afterCompletion threw exception", tsex);
                }
            }
        }
    }
可以看到TransactionSynchronizationUtils的invokeAfterCompletion方法会遍历synchronizations,挨个执行afterCompletion,注意这里catch了Throwable异常,进行了error级别的log

AbstractPlatformTransactionManager

org/springframework/transaction/support/AbstractPlatformTransactionManager.java

    /**
     * Actually invoke the {@code afterCompletion} methods of the
     * given Spring TransactionSynchronization objects.
     * <p>To be called by this abstract manager itself, or by special implementations
     * of the {@code registerAfterCompletionWithExistingTransaction} callback.
     * @param synchronizations a List of TransactionSynchronization objects
     * @param completionStatus the completion status according to the
     * constants in the TransactionSynchronization interface
     * @see #registerAfterCompletionWithExistingTransaction(Object, java.util.List)
     * @see TransactionSynchronization#STATUS_COMMITTED
     * @see TransactionSynchronization#STATUS_ROLLED_BACK
     * @see TransactionSynchronization#STATUS_UNKNOWN
     */
    protected final void invokeAfterCompletion(List<TransactionSynchronization> synchronizations, int completionStatus) {
        TransactionSynchronizationUtils.invokeAfterCompletion(synchronizations, completionStatus);
    }

    /**
     * Trigger {@code afterCompletion} callbacks.
     * @param status object representing the transaction
     * @param completionStatus completion status according to TransactionSynchronization constants
     */
    private void triggerAfterCompletion(DefaultTransactionStatus status, int completionStatus) {
        if (status.isNewSynchronization()) {
            List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
            TransactionSynchronizationManager.clearSynchronization();
            if (!status.hasTransaction() || status.isNewTransaction()) {
                if (status.isDebug()) {
                    logger.trace("Triggering afterCompletion synchronization");
                }
                // No transaction or new transaction for the current scope ->
                // invoke the afterCompletion callbacks immediately
                invokeAfterCompletion(synchronizations, completionStatus);
            }
            else if (!synchronizations.isEmpty()) {
                // Existing transaction that we participate in, controlled outside
                // of the scope of this Spring transaction manager -> try to register
                // an afterCompletion callback with the existing (JTA) transaction.
                registerAfterCompletionWithExistingTransaction(status.getTransaction(), synchronizations);
            }
        }
    }
AbstractPlatformTransactionManager的invokeAfterCompletion委托给了TransactionSynchronizationUtils.invokeAfterCompletion;triggerAfterCompletion主要是根据事务状态执行不同逻辑,分别是invokeAfterCompletion与registerAfterCompletionWithExistingTransaction,后者主要是JTA之类的场景,它回传的status是STATUS_UNKNOWN

小结

afterCompletion方法有入参status,表示事务结束时候的状态,0表示事务已提交,1表示事务已回滚,2表示事务未知(一般是JTA相关);与afterCommit的一个最重要的区别是afterCompletion的异常(Throwable)会被捕获,不像afterCommit会抛给调用方

doc


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...