文章目录
- 前言
- Spring事务详解连载
- TransactionSynchronization
- afterCommit方法分析
- 1.找到方法调用的入口
- TransactionTemplate
- AbstractPlatformTransactionManager
- TransactionSynchronizationUtils
- 2.获取TransactionSynchronization集合
- getSynchronizations
- 添加元素
- 4.实际使用方式
前言
beforeCommit、beforeCompletion、afterCommit、afterCompletion
是Spring为我们在事务提交前、后提供的扩展点,业务在实际使用时可以通过这几个方法在事务提交前、后实现一些额外的逻辑控制,尤其是有些需要在事务提交后才能处理的逻辑,利用afterCommit
或者afterCompletion
可以非常方便的实现,本文就来简单分析一下Spring是通过什么样的方式来预埋这几个方法的。
Spring事务详解连载
【Spring事务详解】— 1.事务传播的案例演示
【Spring事务详解】— 2.事务应用的注意事项
【Spring事务详解】— 3.事务失效的八种场景
【Spring事务详解】— 4.事务管理器的架构分析
【Spring事务详解】— 5.事务管理器TransactionSynchronizationManager分析
【Spring事务详解】— 6.事务创建的流程分析
【Spring事务详解】— 7.事务提交、回滚的流程分析
【Spring事务详解】— 、beforeCompletion、afterCommit、afterCompletion实现分析
TransactionSynchronization
首先这几个方法是定义在TransactionSynchronization
接口中的,并且定义的都是default
方法,默认没有任何处理。
public interface TransactionSynchronization extends Ordered, Flushable {
default void beforeCommit(boolean readOnly) {
}
default void beforeCompletion() {
}
default void afterCommit() {
}
default void afterCompletion(int status) {
}
}
afterCommit方法分析
以afterCommit
方法为例,我们来简单分析一下实现逻辑,其他的3个实现方法大体一致。
1.找到方法调用的入口
TransactionTemplate
如果你使用的是编程式事务,那么TransactionTemplate
类的execute
方法则是整个事务执行的入口,由于我们只分析afterCommit
的实现逻辑,所以我们直接看相关方法即可,在exceute
中,就是方法。
public <T> T execute(TransactionCallback<T> action) throws TransactionException {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) {
return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action);
}
else {
TransactionStatus status = this.transactionManager.getTransaction(this);
T result;
try {
result = action.doInTransaction(status);
}
catch (RuntimeException | Error ex) {
// Transactional code threw application exception -> rollback
rollbackOnException(status, ex);
throw ex;
}
catch (Throwable ex) {
// Transactional code threw unexpected exception -> rollback
rollbackOnException(status, ex);
throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception");
}
// 当前面事务处理完成之后,直接调用事务提交的方法。
this.transactionManager.commit(status);
return result;
}
}
AbstractPlatformTransactionManager
如果是使用声明式事务,那么入口就是commit
方法。
事务提交的方法由AbstractPlatformTransactionManager
控制,逻辑也很明显,processCommit
是真正的执行方法。
@Override
public final void commit(TransactionStatus status) throws TransactionException {
if (status.isCompleted()) {
throw new IllegalTransactionStateException(
"Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
if (defStatus.isLocalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Transactional code has requested rollback");
}
processRollback(defStatus, false);
return;
}
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
if (defStatus.isDebug()) {
logger.debug("Global transaction is marked as rollback-only but transactional code requested commit");
}
processRollback(defStatus, true);
return;
}
processCommit(defStatus);
}
// processCommit方法定义了流程处理的主体结构,然后通过doCommit方法,让具体的事务管理器去实现。
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
boolean beforeCompletionInvoked = false;
try {
boolean unexpectedRollback = false;
prepareForCommit(status);
// 这两步就对应这beforeCommit、beforeCompletion的逻辑
triggerBeforeCommit(status);
triggerBeforeCompletion(status);
beforeCompletionInvoked = true;
if (status.hasSavepoint()) {
if (status.isDebug()) {
logger.debug("Releasing transaction savepoint");
}
unexpectedRollback = status.isGlobalRollbackOnly();
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
if (status.isDebug()) {
logger.debug("Initiating transaction commit");
}
unexpectedRollback = status.isGlobalRollbackOnly();
// 真正执行事务提交的方法,交给了具体的事务处理器去执行
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
unexpectedRollback = status.isGlobalRollbackOnly();
}
// Throw UnexpectedRollbackException if we have a global rollback-only
// marker but still didn't get a corresponding exception from commit.
if (unexpectedRollback) {
throw new UnexpectedRollbackException(
"Transaction silently rolled back because it has been marked as rollback-only");
}
}
catch (UnexpectedRollbackException ex) {
// can only be caused by doCommit
triggerAfterCompletion(status, TransactionSynchronization.STATUS_ROLLED_BACK);
throw ex;
}
catch (TransactionException ex) {
// can only be caused by doCommit
if (isRollbackOnCommitFailure()) {
doRollbackOnCommitException(status, ex);
}
else {
triggerAfterCompletion(status, TransactionSynchronization.STATUS_UNKNOWN);
}
throw ex;
}
catch (RuntimeException | Error ex) {
if (!beforeCompletionInvoked) {
triggerBeforeCompletion(status);
}
doRollbackOnCommitException(status, ex);
throw ex;
}
// Trigger afterCommit callbacks, with an exception thrown there
// propagated to callers but the transaction still considered as committed.
try {
// 当事务提交成功之后,调用triggerAfterCommit方法,afterCommit逻辑入口也在这
triggerAfterCommit(status);
}
finally {
// afterCompletion的入口。
triggerAfterCompletion(status, TransactionSynchronization.STATUS_COMMITTED);
}
}
finally {
cleanupAfterCompletion(status);
}
}
// 调用TransactionSynchronizationUtils类的triggerAfterCommit方法
private void triggerAfterCommit(DefaultTransactionStatus status) {
if (status.isNewSynchronization()) {
TransactionSynchronizationUtils.triggerAfterCommit();
}
}
TransactionSynchronizationUtils
到了TransactionSynchronizationUtils
之后,处理流程就很简单了,获取TransactionSynchronization
集合,挨个遍历调用即可。
public static void triggerAfterCommit() {
invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations());
}
public static void invokeAfterCommit(@Nullable List<TransactionSynchronization> synchronizations) {
if (synchronizations != null) {
for (TransactionSynchronization synchronization : synchronizations) {
// 最终调用到afterCommit方法
synchronization.afterCommit();
}
}
}
通过以上的流程分析可以看出,Spring就是简单的把执行afterCommit
方法放在事务提交后调用。
2.获取TransactionSynchronization集合
根据前面的流程分析可能,synchronizations
集合是通过调用()
方法获取的。
public static void triggerAfterCommit() {
invokeAfterCommit(TransactionSynchronizationManager.getSynchronizations());
}
getSynchronizations
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations =
new NamedThreadLocal<>("Transaction synchronizations");
public static List<TransactionSynchronization> getSynchronizations() throws IllegalStateException {
// synchronizations是TransactionSynchronizationManager类中定义的一个ThreadLocal全局变量
Set<TransactionSynchronization> synchs = synchronizations.get();
// 如果为null,则抛出异常
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
}
// Return unmodifiable snapshot, to avoid ConcurrentModificationExceptions
// while iterating and invoking synchronization callbacks that in turn
// might register further synchronizations.
// 为空,直接返回
if (synchs.isEmpty()) {
return Collections.emptyList();
}
else {
// Sort lazily here, not in registerSynchronization.
// 排序后,返回集合快照
List<TransactionSynchronization> sortedSynchs = new ArrayList<>(synchs);
OrderComparator.sort(sortedSynchs);
return Collections.unmodifiableList(sortedSynchs);
}
}
添加元素
很明显,现在问题又变成了synchronizations
这个ThreadLocal
全局变量是何时被赋值的?
首先在事务开始前,就会通过调用initSynchronization
方法,先对其进行初始化,这个方法入口也很容易找到,就在TransactionTemplate
的execute
方法中,通过调用(this)
方法,完成初始化。
public static void initSynchronization() throws IllegalStateException {
if (isSynchronizationActive()) {
throw new IllegalStateException("Cannot activate transaction synchronization - already active");
}
synchronizations.set(new LinkedHashSet<>());
}
TransactionSynchronizationManager
还提供了registerSynchronization
方法可以对其进行添加元素。
public static void registerSynchronization(TransactionSynchronization synchronization)
throws IllegalStateException {
Assert.notNull(synchronization, "TransactionSynchronization must not be null");
Set<TransactionSynchronization> synchs = synchronizations.get();
if (synchs == null) {
throw new IllegalStateException("Transaction synchronization is not active");
}
synchs.add(synchronization);
}
4.实际使用方式
所以,一般我们自定义的方法都是这样实现的,通过匿名类的方式,直接添加一个TransactionSynchronization
类型的元素到synchronizations
集合中
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCompletion(int status) {
// 实现你的业务逻辑,在前面分析的invokeAfterCommit方法中,会调用到这里
}
});