关联博文:
你认真研究过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()方法将会触发CglibMethodInvocation的proceed方法,后置其又会走到父类ReflectiveMethodInvocation的proceed方法,将会触发下一个拦截器。如果没有拦截器(本文这里只有一个拦截器)将会触发真正目标方法的调用。
核心流程如下图
我们接下来逐个分析核心流程的模板方法:
获取事务对象 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
。