SpringBoot中事务执行原理分析(二)

关联博文:
SpringBoot中事务执行原理分析(一)
SpringBoot中事务执行原理分析(二)
SpringBoot中事务执行原理分析(三)
SpringBoot中事务执行原理分析(四)
SpringBoot中事务执行原理分析(五)
SpringBoot中事务执行原理分析(六)
SpringBoot中事务执行原理分析补充篇
你认真研究过Spring中的@EnableTransactionManagement注解吗?

接上文SpringBoot中事务执行原理分析(一)分析后,我们本文详细跟踪下TransactionInterceptor是如何控制事务行为的。

前面我们提到了,我们的service被包装为代理。当触发目标方法时首先触发了DynamicAdvisedInterceptor的intercept方法,我们就从这里开始跟踪。

在这里插入图片描述

【1】前置流程

① 获取方法的拦截器链

首先触发下面这行代码获取方法的拦截器链。

// CglibAopProxy.DynamicAdvisedInterceptor#intercept
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

其本质就是从advised中获取到Advisor然后遍历、判断是否与当前目标类的方法匹配,如果匹配则获取MethodInterceptor。
在这里插入图片描述
关于为目标方法获取拦截器链的详细流程,可以参考博文Spring AOP如何为目标方法创建拦截器链?

本文这里获取到的拦截器链如下图所示只有一个TransactionInterceptor:

在这里插入图片描述

② ReflectiveMethodInvocation的proceed

如果拦截器链不为空,那么将会走到ReflectiveMethodInvocation的proceed方法。在Spring AOP中CGLIB代理对象增强通知执行原理我们详细跟踪过拦截器链的调用。这里我们见到回滚一下。

方法如下所示,其会遍历拦截器链中的每一个元素尝试触发其invoke方法,如果拦截器链执行完,那么将会通过invokeJoinpoint()来触发真正目标方法的执行。

public Object proceed() throws Throwable {
// We start with an index of -1 and increment early.
	if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
		return invokeJoinpoint();
	}

	Object interceptorOrInterceptionAdvice =
			this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
	if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
		// Evaluate dynamic method matcher here: static part will already have
		// been evaluated and found to match.
		InterceptorAndDynamicMethodMatcher dm =
				(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
		Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
		if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {
			return dm.interceptor.invoke(this);
		}
		else {
			// Dynamic matching failed.
			// Skip this interceptor and invoke the next in the chain.
			return proceed();
		}
	}
	else {
		// It's an interceptor, so we just invoke it: The pointcut will have
		// been evaluated statically before this object was constructed.
		return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
	}
}

如下所示,这里我们将会触发TransactionInterceptor的invoke方法。
在这里插入图片描述

【2】核心流程分析

TransactionInterceptor的invoke方法如下所示,首先获取targetClass ,本文这里是class com.recommend.service.impl.SysAdviceServiceImpl。然后触发了invokeWithinTransaction方法。

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
	// Work out the target class: may be {@code null}.
	// The TransactionAttributeSource should be passed the target class
	// as well as the method, which may be from an interface.
	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

方法源码如下所示,这里根据本文情况忽略了一些分支:

// TransactionAspectSupport#invokeWithinTransaction
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {

	// If the transaction attribute is null, the method is non-transactional.
// 获取TransactionAttributeSource ,用于解析事务注解属性,其维护了annotationParsers
	TransactionAttributeSource tas = getTransactionAttributeSource();

//获取事务注解的属性
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);

//根据事务注解属性信息获取事务管理器TransactionManager,本文获取的是DataSourceTransactionManager
	final TransactionManager tm = determineTransactionManager(txAttr);


//响应式事务管理,本文跳过这个
//...

//转换为为PlatformTransactionManager
	PlatformTransactionManager ptm = asPlatformTransactionManager(tm);

//获取方法的描述信息 com.recommend.service.impl.SysAdviceServiceImpl.testSave
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

//这里是事务处理逻辑
	if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		//获取事务对象,这里将会触发事务的创建
		TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);

		Object retVal;
		try {
			// This is an around advice: Invoke the next interceptor in the chain.
			// This will normally result in a target object being invoked.
	//触发CglibMethodInvocation的proceed方法,
	//其又会走到父类ReflectiveMethodInvocation的proceed方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// target invocation exception 触发事务回滚
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
		// 清理事务信息
			cleanupTransactionInfo(txInfo);
		}

		if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
			// Set rollback-only in case of Vavr failure matching our rollback rules...
			TransactionStatus status = txInfo.getTransactionStatus();
			if (status != null && txAttr != null) {
				retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
			}
		}
	//提交事务 
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}

//下面是处理CallbackPreferringPlatformTransactionManager类型,我们可以忽略
	//...
}

方法逻辑梳理如下:

  • 获取TransactionAttributeSource ,用于解析事务注解属性,其维护了annotationParsers
  • 获取事务注解的属性
  • 根据事务注解属性信息获取事务管理器TransactionManager,本文获取的是DataSourceTransactionManager
  • 判断是否为响应式事务,如果是则走该分支,本文跳过这个
  • 将事务管理器转换为为PlatformTransactionManager
  • 获取方法的描述信息 本文这里是com.recommend.service.impl.SysAdviceServiceImpl.testSave
  • 如果txAttr为null,或者事务管理器不是CallbackPreferringPlatformTransactionManager
    • 获取事务对象,这里将会触发事务的创建
    • invocation.proceedWithInvocation()最终会触发目标方法
    • 如果抛出异常触发回滚并抛出异常
    • 清理事务信息
    • 如果没有抛出异常则提交事务
  • 触发CallbackPreferringPlatformTransactionManager的分支
    invocation.proceedWithInvocation()方法将会触发CglibMethodInvocationproceed方法,后置其又会走到父类ReflectiveMethodInvocationproceed方法,将会触发下一个拦截器。如果没有拦截器(本文这里只有一个拦截器)将会触发真正目标方法的调用。
    在这里插入图片描述

核心流程如下图

在这里插入图片描述

我们接下来逐个分析核心流程的模板方法:

  • 获取事务对象 createTransactionIfNecessary
  • 提交事务 commitTransactionAfterReturning(txInfo);
  • 回滚事务 completeTransactionAfterThrowing(txInfo, ex);
  • 清理事务信息 cleanupTransactionInfo(txInfo);

其中清理事务信息较为简单,如下所示其重置了当前线程持有的事务信息。

protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
	if (txInfo != null) {
		txInfo.restoreThreadLocalStatus();
	}
}

private void restoreThreadLocalStatus() {
	// Use stack to restore old transaction TransactionInfo.
	// Will be null if none was set.
	transactionInfoHolder.set(this.oldTransactionInfo);
}

private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
		new NamedThreadLocal<>("Current aspect-driven transaction");

transactionInfoHolder是一个ThreadLocal对象,持有了当前线程上下文的事务信息,这里restoreThreadLocalStatus其实就是将Holder持有的事务信息恢复到前一个事务信息oldTransactionInfo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值