tcc-transaction源码解读

 一.try阶段

入口点PaymentServiceImpl.makePayment方法的@Compensable注解,该注解会被aop拦截。

CompensableTransactionAspect切面拦截进入CompensableTransactionInterceptor的interceptCompensableMethod,此时事务类型ROOT全局事务,执行rootMethodProceed方法,创建全局事务transaction,执行compensableMethodContext.proceed(),此时执行try方法,再次被ResourceCoordinatorAspect切面拦截,由于当前是try阶段,执行enlistParticipant(pjp)。

// 首先要知道,此处compensable注解上没有设置上下文编辑器,则默认为DefaultTransactionContextEditor     
if (FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs()) == null) {
   // 此时set方法相当于空执行,why?
   FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().set(new TransactionContext(xid, TransactionStatus.TRYING.getId()), pjp.getTarget(), ((MethodSignature) pjp.getSignature()).getMethod(), pjp.getArgs());
}

class DefaultTransactionContextEditor implements TransactionContextEditor {
        @Override
        public TransactionContext get(Object target, Method method, Object[] args) {
            int position = getTransactionContextParamPosition(method.getParameterTypes());
            // 先分析get方法,因为makePayment方法中没有TransactionContext类型参数,所以position为-1,get方法返回null
            if (position >= 0) {
                return (TransactionContext) args[position];
            }
            return null;
        }

        @Override
        public void set(TransactionContext transactionContext, Object target, Method method, Object[] args) {
            // 方法中没有TransactionContext类型参数, position为-1
            int position = getTransactionContextParamPosition(method.getParameterTypes());
            if (position >= 0) {
                args[position] = transactionContext;
            }
        }

        public static int getTransactionContextParamPosition(Class<?>[] parameterTypes) {
            int position = -1;
            for (int i = 0; i < parameterTypes.length; i++) {
                if (parameterTypes[i].equals(org.mengyun.tcctransaction.api.TransactionContext.class)) {
                    position = i;
                    break;
                }
            }
            return position;
        }

        public static TransactionContext getTransactionContextFromArgs(Object[] args) {
            TransactionContext transactionContext = null;
            for (Object arg : args) {
                if (arg != null && org.mengyun.tcctransaction.api.TransactionContext.class.isAssignableFrom(arg.getClass())) {
                    transactionContext = (org.mengyun.tcctransaction.api.TransactionContext) arg;
                }
            }
            return transactionContext;
        }
    }

接下来是把xid,confirmInvocation(confirmMakePayment),cancelInvocation(cancelMakePayment)封装成对应的partcipant,加入到当前事务ROOT中。执行pjp.proceed(pjp.getArgs()),此时进入makePayment的try方法中。当调用capitalTradeOrderService的record方法时,由于capitalTradeOrderService通过dubbo接口调用,tcc-transaction为该接口生成了代理对象。
源码见tcc-transaction-dubbo模块

proxy对象(record)
1.首先执行代理对象的record方法,同样会被两个切面拦截,因为生成代理对象的record方法有Compensable注解2.CompensableTransactionAspect切面拦截,直接执行pjp.proceed(),此时是本地代理对象的Normal方法,不是PROVIDER和ROOT类型。
3.ResourceCoordinatorAspect切面拦截执行try阶段逻辑。

由于注解事务上下文类型为DubboTransactionContextEditor,通过dubbo隐式传参设置事务上下文new TransactionContext(xid, TransactionStatus.TRYING.getId()),后续添加事务参与者,执行pjp.proceed(pjp.getArgs())。

dubbo RPC(record)
1.首先被远程服务的CompensableTransactionAspect切面拦截,此时事务类型为PROVIDER,执行providerMethodProceed,当前try阶段,调用transactionManager.propagationNewBegin创建分支事务,事务transaction的xid通过dubbo隐式传参获取,以达到主、分支事务的关联。
2.执行compensableMethodContext.proceed(),即远程record的try方法。
3.被远程服务的ResourceCoordinatorAspect切面拦截,由于try阶段则执行enlistParticipant方法,主要获取分支事务,通过GlobalTransactionId创建xid,隐式传参事务上下文,绑定事务与参与者,调用pjp.proceed(pjp.getArgs()),此时真正执行远程record的try方法逻辑。

redPacketTradeOrderService.record处理流程跟capitalTradeOrderService.record一致,不再赘述。
到此try一阶段结束

二.commit阶段

try阶段执行正常,进行commit提交操作,否则进行rollback操作。commit和rollback执行流程基本一致。
commit提交流程如下

入口点rootMethodProceed方法的transactionManager.commit(asyncConfirm)。

1.首先通过getCurrentTransaction()拿到ROOT主事务,设置状态CONFIRMING,循环事务参与者participant,ROOT主事务包含了三个参与者。confirmMakePayment通过反射直接执行即可。
2.capital record通过terminator.invoker的method.invoke(target, invocationContext.getArgs())反射调用,则还是执行本地代理对象方法,此处调用之前使用了隐式传参。
3.通过AOP切面拦截,进入CompensableTransactionInterceptor,直接执行pjp.proceed()。
4.进入ResourceCoordinatorInterceptor,当前try阶段,break结束,继续执行pjp.proceed(pjp.getArgs())。
5.dubbo远程调用record,此时被远程服务的aop切面拦截, 事务类型PROVIDER,执行providerMethodProceed,当前处于COMFIRMING阶段,执行transactionManager.propagationExistBegin获取分支事务(xid),执行commit方法,同样循环参与者,此时的分支事务只包含一个事务参与者。最终反射调用CapitalTradeOrderServiceImpl的confirmRecord方法进行分支事务的提交。最后从本地线程变量中清除已提交事务。

redpacket record方法与capital完全一致,不再赘述。
最后待分支事务都commit结束,删除ROOT主事务,整个分布式事务执行流程结束。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值