Seata框架源码分析——TCC模式

TCC模式使用示例

本文旨在针对Seata框架的TCC模式的源码进行讲解分析,在此不过多介绍Seata框架。
如果想了解更多有关Seata框架的细节,建议可以阅读我的另外一篇博客:Seata框架源码分析——AT模式

为了更新方便之后的源码分析讲解,首先来看下TCC模式的使用示例:

与AT模式的使用非常类似,TCC模式都是使用注解达到分布式事务控制的效果,使用成本非常低。

业务调用方在接口方法上使用@GlobalTransactional注解,开启全局事务

@Service
public class OrderServiceImpl implements OrderService {

    @Autowired
    OrderDao orderDao;

    @DubboReference
    AccountService accountService;

    @DubboReference
    StorageService storageService;

    @Override
    @GlobalTransactional
    public boolean dealTCC(Order order) {
        // 扣减账户
        Account account = new Account();
        account.setAccountId(order.getAccountId());
        account.setUsed(order.getAmount());
        accountService.prepare(null, account);

        // 扣减库存
        Storage storage = new Storage();
        storage.setStorageId(order.getStorageId());
        storage.setUsed(1);
        storageService.prepare(null, storage);

        // 保存订单
        this.orderDao.insert(order);

        return true;
    }
}

业务提供方则在接口方法上使用@TwoPhaseBusinessAction注解,同时指定同个接口中分支事务提交和回滚的方法名:

  • BusinessActionContext是TCC事务中的上下文
  • @BusinessActionContextParameter注解标注的参数会在上下文中传播,能够在指定的提交和回滚方法中使用
public interface AccountService {

    /**
     * AT 模式
     *
     * @param account
     * @return
     */
    boolean dealAT(Account account);

    /**
     * TCC 模式try方法,用于冻结操作
     *
     * @param actionContext
     * @param account
     * @return
     */
    @TwoPhaseBusinessAction(name = "account-tx", commitMethod = "commit", rollbackMethod = "rollback")
    boolean prepare(BusinessActionContext actionContext, @BusinessActionContextParameter(paramName = "account") Account account);

    /**
     * TCC 模式commit方法,当全部分支事物准备完毕后,TC事务控制器会通知调用此方法提交
     *
     * @param actionContext
     * @return
     */
    boolean commit(BusinessActionContext actionContext);

    /**
     * TCC 模式rollback方法,当全局事务需要回滚的时候,TC事务控制器会通知调用此方法回滚,而不再使用undo日志
     *
     * @param actionContext
     * @return
     */
    boolean rollback(BusinessActionContext actionContext);
}

TCC模式源码分析

有了以上使用示例的了解,接下来就是针对其中的源码实现细节进行分析讲解。
Seata模式很好的融入了Spring框架,因此在系统启动时,会扫描相关的Bean进行初始化,并注入,而这个类就是GlobalTransactionScanner:

public class GlobalTransactionScanner extends AbstractAutoProxyCreator
    implements ConfigurationChangeListener, InitializingBean, ApplicationContextAware, DisposableBean {
	...
}

在GlobalTransactionScanner中最主要的动作有两个:

  1. 初始化拦截器(基于注解使用的框架,都是使用拦截的方式对原方法进行增强,Seata亦是如此)
  2. 初始化TM、RM客户端(在本文中不在赘述,因为此部分已在AT模式源码分析中详细讲解)
  • 初始化拦截器
@Override
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    if (!doCheckers(bean, beanName)) { // bean校验
        return bean;
    }
    try {
        synchronized (PROXYED_SET) { // 同步的方式初始化bean
            if (PROXYED_SET.contains(beanName)) {
                return bean;
            }
            interceptor = null; // 拦截器
            // 判断初始化的bean是属于TCC模式,还是AT模式。不同的模式需要初始化的拦截器不同
            // TCC模式:TccActionInterceptor
            // AT模式:GlobalTransactionalInterceptor
            if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) { // TCC模式
                interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
                ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)interceptor);
            } else { // AT模式
                Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);
                Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);
                if (!existsAnnotation(new Class[]{serviceInterface}) && !existsAnnotation(interfacesIfJdk)) {
                    return bean;
                }
                if (globalTransactionalInterceptor == null) {
                    globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
                    ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)globalTransactionalInterceptor);
                }
                interceptor = globalTransactionalInterceptor;
            }

            LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName());
            if (!AopUtils.isAopProxy(bean)) {
                bean = super.wrapIfNecessary(bean, beanName, cacheKey);
            } else {
                AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);
                Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));
                int pos;
                for (Advisor avr : advisor) {
                    // Find the position based on the advisor's order, and add to advisors by pos
                    pos = findAddSeataAdvisorPosition(advised, avr);
                    advised.addAdvisor(pos, avr);
                }
            }
            PROXYED_SET.add(beanName);
            return bean;
        }
    } catch (Exception exx) {
        throw new RuntimeException(exx);
    }
}

由以上wrapIfNecessary方法可以看到,初始化拦截器的关键点是TCCBeanParserUtils.isTccAutoProxy方法,判断该Bean是否属于TCC模式:

public static boolean isTccAutoProxy(Object bean, String beanName, ApplicationContext applicationContext) {
    boolean isRemotingBean = parserRemotingServiceInfo(bean, beanName); // 解析bean信息
    //get RemotingBean description
    RemotingDesc remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
    //is remoting bean
    if (isRemotingBean) {
        if (remotingDesc != null && remotingDesc.getProtocol() == Protocols.IN_JVM) {
            //LocalTCC
            return isTccProxyTargetBean(remotingDesc); // 判断bean是否属于TCC模式
        } else {
            // sofa:reference / dubbo:reference, factory bean
            return false;
        }
    } else {
        if (remotingDesc == null) {
            //check FactoryBean
            if (isRemotingFactoryBean(bean, beanName, applicationContext)) {
                remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
                return isTccProxyTargetBean(remotingDesc);
            } else {
                return false;
            }
        } else {
            return isTccProxyTargetBean(remotingDesc);
        }
    }
}

解析bean,并注册TCC模式的RM资源管理器:

protected static boolean parserRemotingServiceInfo(Object bean, String beanName) {
    RemotingParser remotingParser = DefaultRemotingParser.get().isRemoting(bean, beanName);
    if (remotingParser != null) {
        return DefaultRemotingParser.get().parserRemotingServiceInfo(bean, beanName, remotingParser) != null; // 解析bean信息
    }
    return false;
}
public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, RemotingParser remotingParser) {
    RemotingDesc remotingBeanDesc = remotingParser.getServiceDesc(bean, beanName);
    if (remotingBeanDesc == null) {
        return null;
    }
    remotingServiceMap.put(beanName, remotingBeanDesc); // 将bean缓存起来
    Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass(); // 获取bean接口类
    Method[] methods = interfaceClass.getMethods(); // 获取bean接口类的所有方法
    if (remotingParser.isService(bean, beanName)) {
        try {
            Object targetBean = remotingBeanDesc.getTargetBean();
            for (Method m : methods) { // 遍历方法
	            // 判断方法上是否有标注@TwoPhaseBusinessAction注解
                TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class);
                if (twoPhaseBusinessAction != null) {
                	// 注解不为空,说明该bean属于TCC模式,以下封装TCC相关资源信息,并进行注册
                    TCCResource tccResource = new TCCResource();
                    tccResource.setActionName(twoPhaseBusinessAction.name());
                    tccResource.setTargetBean(targetBean);
                    tccResource.setPrepareMethod(m);
                    tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod()); // 设置指定的提交方法名
                    tccResource.setCommitMethod(interfaceClass.getMethod(twoPhaseBusinessAction.commitMethod(),
                            twoPhaseBusinessAction.commitArgsClasses())); // 设置指定的提交方法对象
                    tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod()); // 设置指定的回滚方法名
                    tccResource.setRollbackMethod(interfaceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(),
                            twoPhaseBusinessAction.rollbackArgsClasses())); // 设置指定的回滚方法对象
                    // 设置提交/回滚方法参数类型
                    tccResource.setCommitArgsClasses(twoPhaseBusinessAction.commitArgsClasses());
                    tccResource.setRollbackArgsClasses(twoPhaseBusinessAction.rollbackArgsClasses());
                    // set phase two method's keys
                    tccResource.setPhaseTwoCommitKeys(this.getTwoPhaseArgs(tccResource.getCommitMethod(),
                            twoPhaseBusinessAction.commitArgsClasses()));
                    tccResource.setPhaseTwoRollbackKeys(this.getTwoPhaseArgs(tccResource.getRollbackMethod(),
                            twoPhaseBusinessAction.rollbackArgsClasses()));
                    // 注册TCC资源,在后期需要获取此资源,调用其中提交/回滚方法
                    DefaultResourceManager.get().registerResource(tccResource);
                }
            }
        } catch (Throwable t) {
            throw new FrameworkException(t, "parser remoting service error");
        }
    }
    if (remotingParser.isReference(bean, beanName)) {
        //reference bean, TCC proxy
        remotingBeanDesc.setReference(true);
    }
    return remotingBeanDesc;
}

注册TCC资源:

@Override
public void registerResource(Resource resource) {
    getResourceManager(resource.getBranchType()).registerResource(resource);
}
@Override
public void registerResource(Resource resource) {
    TCCResource tccResource = (TCCResource)resource;
    tccResourceCache.put(tccResource.getResourceId(), tccResource); // 本地缓存TCC资源
    super.registerResource(tccResource); // 调用父类注册方法
}
@Override
public void registerResource(Resource resource) {
	// TC服务端注册TCC资源
    RmNettyRemotingClient.getInstance().registerResource(resource.getResourceGroupId(), resource.getResourceId());
}

经过TCC资源的注册,可以知道在分支事务的本地会根据资源id对资源进行缓存,以及TC服务端针对该资源注册(远程注册逻辑不是重点,不分析,有兴趣的朋友可以自行研究DefaultServerMessageListenerImp.onRegRmMessage方法)。

  • 全局事务拦截

对于注解来说,首先拦截的业务调用方的@GlobalTransactional。拦截的类方法则是GlobalTransactionalInterceptor.invoke

@Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
    Class<?> targetClass = methodInvocation.getThis() != null ? AopUtils.getTargetClass(methodInvocation.getThis()) : null;
    Method specificMethod = ClassUtils.getMostSpecificMethod(methodInvocation.getMethod(), targetClass);
    if (specificMethod != null && !specificMethod.getDeclaringClass().equals(Object.class)) {
        final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
        final GlobalTransactional globalTransactionalAnnotation = getAnnotation(method, targetClass, GlobalTransactional.class); // 获取拦截方法上的@GlobalTransactional注解
        final GlobalLock globalLockAnnotation = getAnnotation(method, targetClass, GlobalLock.class);
        boolean localDisable = disable || (degradeCheck && degradeNum >= degradeCheckAllowTimes);
        if (!localDisable) { // 判断本地是否允许开启分布式事务
            if (globalTransactionalAnnotation != null) { // 注解不为空,则说明拦截的方法上有@GlobalTransactional注解,开启分布式事务
                return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
            } else if (globalLockAnnotation != null) {
                return handleGlobalLock(methodInvocation, globalLockAnnotation);
            }
        }
    }
    return methodInvocation.proceed(); // 本地不允许开启分布式事务/拦截方法上没有@GlobalTransactional注解,则按原方法执行
}

全局事务拦截这部分源码与AT模式如出一辙,最后具体是通过调用TransactionalTemplate.execute方法实现本地事务执行:

public Object execute(TransactionalExecutor business) throws Throwable {
    TransactionInfo txInfo = business.getTransactionInfo(); // 获取事务相关信息
    if (txInfo == null) {
        throw new ShouldNeverHappenException("transactionInfo does not exist");
    }
    GlobalTransaction tx = GlobalTransactionContext.getCurrent(); // 获取当前事务对象(主要是通过全局事务XID进行判断)
    Propagation propagation = txInfo.getPropagation(); // 获取事务信息中的事务传播级别
    SuspendedResourcesHolder suspendedResourcesHolder = null;
    try {
        // 针对各个事务级别做特殊处理,在此不多讲,继续往下看
        switch (propagation) {
            case NOT_SUPPORTED:
                // If transaction is existing, suspend it.
                if (existingTransaction(tx)) {
                    suspendedResourcesHolder = tx.suspend();
                }
                // Execute without transaction and return.
                return business.execute();
            case REQUIRES_NEW:
                // If transaction is existing, suspend it, and then begin new transaction.
                if (existingTransaction(tx)) {
                    suspendedResourcesHolder = tx.suspend();
                    tx = GlobalTransactionContext.createNew();
                }
                // Continue and execute with new transaction
                break;
            case SUPPORTS:
                // If transaction is not existing, execute without transaction.
                if (notExistingTransaction(tx)) {
                    return business.execute();
                }
                // Continue and execute with new transaction
                break;
            case REQUIRED:
                // If current transaction is existing, execute with current transaction,
                // else continue and execute with new transaction.
                break;
            case NEVER:
                // If transaction is existing, throw exception.
                if (existingTransaction(tx)) {
                    throw new TransactionException(
                        String.format("Existing transaction found for transaction marked with propagation 'never', xid = %s"
                                , tx.getXid()));
                } else {
                    // Execute without transaction and return.
                    return business.execute();
                }
            case MANDATORY:
                // If transaction is not existing, throw exception.
                if (notExistingTransaction(tx)) {
                    throw new TransactionException("No existing transaction found for transaction marked with propagation 'mandatory'");
                }
                // Continue and execute with current transaction.
                break;
            default:
                throw new TransactionException("Not Supported Propagation:" + propagation);
        }

        if (tx == null) { // 当前事务对象为空,说明当前未开启事务,新建事务对象
            tx = GlobalTransactionContext.createNew();
        }
        GlobalLockConfig previousConfig = replaceGlobalLockConfig(txInfo);
        try {
            beginTransaction(txInfo, tx); // 开启事务(重点)
            Object rs;
            try {
                rs = business.execute(); // 执行原方法
            } catch (Throwable ex) {
                completeTransactionAfterThrowing(txInfo, tx, ex); // 原方法执行异常,回滚(重点)
                throw ex;
            }
            commitTransaction(tx); // 原方法执行无异常,提交(重点)
            return rs;
        } finally {
            // clear
            resumeGlobalLockConfig(previousConfig);
            triggerAfterCompletion();
            cleanUp();
        }
    } finally {
        // If the transaction is suspended, resume it.
        if (suspendedResourcesHolder != null) {
            tx.resume(suspendedResourcesHolder);
        }
    }
}

在上面的execute方法中看到,开启事务、执行原方法、成功提交事务、失败回滚事务 这些关键方法。但是对于TCC模式来说,只有当business.execute()执行原方法时,才会调用到其中标注了@TwoPhaseBusinessAction注解方法,该注解才会被拦截增强,TCC模式才会真正生效。
而拦截这个注解的类方法,就是本文开头所讲解的初始化拦截器TccActionInterceptor.invoke:

@Override
public Object invoke(final MethodInvocation invocation) throws Throwable {
    if (!RootContext.inGlobalTransaction() || disable || RootContext.inSagaBranch()) { // 检查是否允许启用全局事务
        return invocation.proceed(); // 禁止启用,直接原方法执行
    }
    Method method = getActionInterfaceMethod(invocation);
    TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class); // 获取方法上的TwoPhaseBusinessAction注解
    if (businessAction != null) { // 注解不为空,则说明是TCC模式
        String xid = RootContext.getXID(); // 获取全局事务ID
        BranchType previousBranchType = RootContext.getBranchType();
        if (BranchType.TCC != previousBranchType) {
            RootContext.bindBranchType(BranchType.TCC);
        }
        try {
            // 处理TCC模式方法
            return actionInterceptorHandler.proceed(method, invocation.getArguments(), xid, businessAction, invocation::proceed); 
        } finally {
            //if not TCC, unbind branchType
            if (BranchType.TCC != previousBranchType) {
                RootContext.unbindBranchType();
            }
            //MDC remove branchId
            MDC.remove(RootContext.MDC_KEY_BRANCH_ID);
        }
    }

    return invocation.proceed(); // 注解为空,则说明不是TCC模式,直接原方法执行
}

TCC注解拦截处理,注册分支事务,并返回绑定分支事务ID:

public Object proceed(Method method, Object[] arguments, String xid, TwoPhaseBusinessAction businessAction, Callback<Object> targetCallback) throws Throwable {
    // 封装TCC上下文信息
    String actionName = businessAction.name();
    BusinessActionContext actionContext = new BusinessActionContext();
    actionContext.setXid(xid);
    actionContext.setActionName(actionName);
    // 注册分支事务,并返回绑定分支事务ID
    String branchId = doTccActionLogStore(method, arguments, businessAction, actionContext);
    actionContext.setBranchId(branchId);
    MDC.put(RootContext.MDC_KEY_BRANCH_ID, branchId);

    Class<?>[] types = method.getParameterTypes();
    int argIndex = 0;
    for (Class<?> cls : types) {
        if (cls.isAssignableFrom(BusinessActionContext.class)) {
            arguments[argIndex] = actionContext;
            break;
        }
        argIndex++;
    }

    BusinessActionContext previousActionContext = BusinessActionContextUtil.getContext(); // 获取前一个上下文对象(即当前上下文对象)
    try {
        BusinessActionContextUtil.setContext(actionContext); // 替换上下文对象
        if (businessAction.useTCCFence()) {
            try {
                // Use TCC Fence, and return the business result
                return TCCFenceHandler.prepareFence(xid, Long.valueOf(branchId), actionName, targetCallback);
            } catch (FrameworkException | UndeclaredThrowableException e) {
                Throwable originException = e.getCause();
                if (originException instanceof FrameworkException) {
                    LOGGER.error("[{}] prepare TCC fence error: {}", xid, originException.getMessage());
                }
                throw originException;
            }
        } else {
            //Execute business, and return the business result
            return targetCallback.execute();
        }
    } finally {
        try {
            //to report business action context finally if the actionContext.getUpdated() is true
            BusinessActionContextUtil.reportContext(actionContext);
        } finally {
            if (previousActionContext != null) {
                // recovery the previous action context
                BusinessActionContextUtil.setContext(previousActionContext);
            } else {
                // clear the action context
                BusinessActionContextUtil.clear();
            }
        }
    }
}
protected String doTccActionLogStore(Method method, Object[] arguments, TwoPhaseBusinessAction businessAction, BusinessActionContext actionContext) {
    // 初始化上下文
    String actionName = actionContext.getActionName();
    String xid = actionContext.getXid();
    Map<String, Object> context = fetchActionRequestContext(method, arguments);
    context.put(Constants.ACTION_START_TIME, System.currentTimeMillis());
    initBusinessContext(context, method, businessAction);
    initFrameworkContext(context);
    actionContext.setDelayReport(businessAction.isDelayReport());
    actionContext.setActionContext(context);
    Map<String, Object> applicationContext = Collections.singletonMap(Constants.TCC_ACTION_CONTEXT, context);
    String applicationContextStr = JSON.toJSONString(applicationContext);
    try {
        // 注册分支事务,并返回分支ID
        Long branchId = DefaultResourceManager.get().branchRegister(BranchType.TCC, actionName, null, xid, applicationContextStr, null);
        return String.valueOf(branchId);
    } catch (Throwable t) {
        String msg = String.format("TCC branch Register error, xid: %s", xid);
        LOGGER.error(msg, t);
        throw new FrameworkException(t, msg);
    }
}

到此,TC、TM、RM、分支事务都初始化和注册完毕。接下来就是正常执行业务代码,当业务代码执行无异常(即分支事务全部执行成功),则需要进行全局事务提交(回到源码分析开头business.execute成功之后):

private void commitTransaction(GlobalTransaction tx) throws TransactionalExecutor.ExecutionException {
    try {
        triggerBeforeCommit();
        tx.commit();
        triggerAfterCommit();
    } catch (TransactionException txe) {
        // 4.1 Failed to commit
        throw new TransactionalExecutor.ExecutionException(tx, txe, TransactionalExecutor.Code.CommitFailure);
    }
}
@Override
public void commit() throws TransactionException {
    if (role == GlobalTransactionRole.Participant) {
        // Participant has no responsibility of committing
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Ignore Commit(): just involved in global transaction [{}]", xid);
        }
        return;
    }
    assertXIDNotNull();
    int retry = COMMIT_RETRY_COUNT <= 0 ? DEFAULT_TM_COMMIT_RETRY_COUNT : COMMIT_RETRY_COUNT;
    try {
        while (retry > 0) {
            try {
                status = transactionManager.commit(xid); // 提交事务
                break;
            } catch (Throwable ex) {
                LOGGER.error("Failed to report global commit [{}],Retry Countdown: {}, reason: {}", this.getXid(), retry, ex.getMessage());
                retry--;
                if (retry == 0) {
                    throw new TransactionException("Failed to report global commit", ex);
                }
            }
        }
    } finally {
        if (xid.equals(RootContext.getXID())) {
            suspend();
        }
    }
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("[{}] commit status: {}", xid, status);
    }
}

发送请求通知TC服务端全局事务提交:

@Override
public GlobalStatus commit(String xid) throws TransactionException {
    GlobalCommitRequest globalCommit = new GlobalCommitRequest();
    globalCommit.setXid(xid);
    GlobalCommitResponse response = (GlobalCommitResponse) syncCall(globalCommit);
    return response.getGlobalStatus();
}

在TC收到全局事务提交的消息后,会发送响应请求告知RM分支事务,执行TCC模式指定的commit方法(RM在AbstractRMHandler.handle方法中处理TC提交分支事务请求):

@Override
public BranchCommitResponse handle(BranchCommitRequest request) {
    BranchCommitResponse response = new BranchCommitResponse();
    exceptionHandleTemplate(new AbstractCallback<BranchCommitRequest, BranchCommitResponse>() {
        @Override
        public void execute(BranchCommitRequest request, BranchCommitResponse response) throws TransactionException {
            doBranchCommit(request, response); // 分支事务提交
        }
    }, request, response);
    return response;
}

handle方法有两个,有提交、回滚,以上方法是属于提交分支事务方法(回滚方法的逻辑大基本一致,不赘述):

protected void doBranchCommit(BranchCommitRequest request, BranchCommitResponse response) throws TransactionException {
    String xid = request.getXid();
    long branchId = request.getBranchId();
    String resourceId = request.getResourceId();
    String applicationData = request.getApplicationData();
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("Branch committing: " + xid + " " + branchId + " " + resourceId + " " + applicationData);
    }
    // 获取资源管理器,并执行分支事务提交方法
    BranchStatus status = getResourceManager().branchCommit(request.getBranchType(), xid, branchId, resourceId, applicationData);
    response.setXid(xid);
    response.setBranchId(branchId);
    response.setBranchStatus(status);
    if (LOGGER.isInfoEnabled()) {
        LOGGER.info("Branch commit result: " + status);
    }
}
@Override
public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId, String applicationData) throws TransactionException {
    TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId); // 根据资源ID从缓存中获取对应的TCC资源(在TCC模式注册分支时候存入缓存)
    if (tccResource == null) {
        throw new ShouldNeverHappenException(String.format("TCC resource is not exist, resourceId: %s", resourceId));
    }
    Object targetTCCBean = tccResource.getTargetBean();
    Method commitMethod = tccResource.getCommitMethod(); // 获取TCC资源的commit提交方法
    if (targetTCCBean == null || commitMethod == null) {
        throw new ShouldNeverHappenException(String.format("TCC resource is not available, resourceId: %s", resourceId));
    }
    try {
        // 获取上下文信息
        BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId, applicationData);
        Object[] args = this.getTwoPhaseCommitArgs(tccResource, businessActionContext);
        Object ret;
        boolean result;
        // 利用反射机制执行commit方法,完成分支事务的提交
        if (Boolean.TRUE.equals(businessActionContext.getActionContext(Constants.USE_TCC_FENCE))) {
            try {
                result = TCCFenceHandler.commitFence(commitMethod, targetTCCBean, businessActionContext, xid, branchId, args);
            } catch (FrameworkException | UndeclaredThrowableException e) {
                throw e.getCause();
            }
        } else {
            ret = commitMethod.invoke(targetTCCBean, args);
            if (ret != null) {
                if (ret instanceof TwoPhaseResult) {
                    result = ((TwoPhaseResult)ret).isSuccess();
                } else {
                    result = (boolean)ret;
                }
            } else {
                result = true;
            }
        }
        LOGGER.info("TCC resource commit result : {}, xid: {}, branchId: {}, resourceId: {}", result, xid, branchId, resourceId);
        return result ? BranchStatus.PhaseTwo_Committed : BranchStatus.PhaseTwo_CommitFailed_Retryable;
    } catch (Throwable t) {
        String msg = String.format("commit TCC resource error, resourceId: %s, xid: %s.", resourceId, xid);
        LOGGER.error(msg, t);
        return BranchStatus.PhaseTwo_CommitFailed_Retryable;
    }
}

至此结束,以上便是Seata框架的TCC模式源码分析。
因为本文中很多内容在AT模式的源码分析文章已经详细介绍过(例如:TM、RM、TC之间的关系图解,TM、RM客户端的初始化,以及分支事务的数据库相关代理类等等),所以在本文中就不过多赘述,如果想更详细了解相关源码,可以访问本文开头的AT模式文章链接。

你可能感兴趣的:(java,后端,Seata,分布式事务)