Seata TCC模式源码解析

  前文已经讲解了AT模式的流程,现在接着看到TCC模式的源码。有了前面的基础,我们直接看到GlobalTransactionScanner类的wrapIfNecessary方法

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
        try {
            synchronized (PROXYED_SET) {
                if (PROXYED_SET.contains(beanName)) {
                    return bean;
                }
                interceptor = null;
                //看这里,判断是否生成TCC模式的切面
                //check TCC proxy
                if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
                    //TCC interceptor, proxy bean of sofa:reference/dubbo:reference, and LocalTCC			
                    //TCC模式的拦截器TccActionInterceptor
                    interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
                    ConfigurationCache.addConfigListener(ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION,
                        (ConfigurationChangeListener)interceptor);
                } else {
                    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));
                    for (Advisor avr : advisor) {
                        advised.addAdvisor(0, avr);
                    }
                }
                PROXYED_SET.add(beanName);
                return bean;
            }
        } catch (Exception exx) {
            throw new RuntimeException(exx);
        }
    }
public static boolean isTccAutoProxy(Object bean, String beanName, ApplicationContext applicationContext) {
		//判断接口是否有@LocalTCC注解
        boolean isRemotingBean = parserRemotingServiceInfo(bean, beanName);
        //get RemotingBean description
        //判断remotingServiceMap是否存在该bean
        RemotingDesc remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
        //is remoting bean
        if (isRemotingBean) {
        	//remotingDesc.getProtocol() == Protocols.IN_JVM判断是否为本地bean
            if (remotingDesc != null && remotingDesc.getProtocol() == Protocols.IN_JVM) {
                //LocalTCC
                //如果接口有方法有@TwoPhaseBusinessAction注解修饰,且为本地bean,返回为true
                return isTccProxyTargetBean(remotingDesc);
            } else {  
                // sofa:reference / dubbo:reference, factory bean
                return false;
            }
        } 
        else {
            if (remotingDesc == null) {
                //check FactoryBean
                //判断是否为factoryBean类型,使用原始bean(applicationContext.getBean(&beanName))再次去检查TCC相关注解,如果有,一样可以生成TCC的代理
                if (isRemotingFactoryBean(bean, beanName, applicationContext)) {
                    remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(beanName);
                    return isTccProxyTargetBean(remotingDesc);
                } else {
                    return false;
                }
            } else {
                return isTccProxyTargetBean(remotingDesc);
            }
        }
}

protected static boolean parserRemotingServiceInfo(Object bean, String beanName) {
		//查找@LocalTCC注解
        RemotingParser remotingParser = DefaultRemotingParser.get().isRemoting(bean, beanName);
        if (remotingParser != null) {
        	//如果有@LocalTCC注解
        	//接着查找接口中的方法是否被@TwoPhaseBusinessAction修饰
            return DefaultRemotingParser.get().parserRemotingServiceInfo(bean, beanName, remotingParser) != null;
        }
        return false;
}

//seata-all-1.4.2-sources.jar的meta-inf的services中有多个实现了RemotingParser接口的解析类
//LocalTCCRemotingParser的isRemoting方法,LocalTCCRemotingParser的isReference和isService是一样的
public boolean isRemoting(Object bean, String beanName) throws FrameworkException {
        return isReference(bean, beanName) || isService(bean, beanName);
}
public boolean isReference(Object bean, String beanName) {
        Class<?> classType = bean.getClass();
        //获取类实现的接口
        Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType);
        //循环判断是否有@LocalTCC注解
        for (Class<?> interClass : interfaceClasses) {
            if (interClass.isAnnotationPresent(LocalTCC.class)) {
                return true;
            }
        }
        return false;
}

public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, RemotingParser remotingParser) {
		//将该bean包装为RemotingDesc类型
        RemotingDesc remotingBeanDesc = remotingParser.getServiceDesc(bean, beanName);
        if (remotingBeanDesc == null) {
            return null;
        }
        //remotingServiceMap中放入beanName和remotingBeanDesc的映射关系
        remotingServiceMap.put(beanName, remotingBeanDesc);
		
		//获取实现的接口类型
        Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass();
        //获取接口中的方法
        Method[] methods = interfaceClass.getMethods();
   		
        if (remotingParser.isService(bean, beanName)) {
            try {
                //service bean, registry resource
                //获取目标bean,
                Object targetBean = remotingBeanDesc.getTargetBean();
                //循环遍历所有的方法
                for (Method m : methods) {
                    TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class);
                    //方法上有被@TwoPhaseBusinessAction注解修饰
                    if (twoPhaseBusinessAction != null) {
                    	//封装注解的属性到TCCResource中
                        TCCResource tccResource = new TCCResource();
                        //设置resourceId属性为注解的name属性值
                        tccResource.setActionName(twoPhaseBusinessAction.name());
                        tccResource.setTargetBean(targetBean);
                        tccResource.setPrepareMethod(m);
                        tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod());
                        tccResource.setCommitMethod(ReflectionUtil
                            .getMethod(interfaceClass, twoPhaseBusinessAction.commitMethod(),
                                new Class[] {BusinessActionContext.class}));
                        tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod());
                        tccResource.setRollbackMethod(ReflectionUtil
                            .getMethod(interfaceClass, twoPhaseBusinessAction.rollbackMethod(),
                                new Class[] {BusinessActionContext.class}));
                        //registry tcc resource
                        //向TCCResourceManager的tccResourceCache(map)建立resourceId和tccResource 的映射关系
                        //并且将该本服务地址和resourceId发送给seata服务端
                        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;
}

  直接看到TccActionInterceptor的invoke方法

public Object invoke(final MethodInvocation invocation) throws Throwable {
		//判断是否有XID ,  是否禁用全局事务  , 是否为sega模式
        if (!RootContext.inGlobalTransaction() || disable || RootContext.inSagaBranch()) {
            //not in transaction
            return invocation.proceed();
        }
        //获取当前调用的接口方法
        Method method = getActionInterfaceMethod(invocation);
       	//拿到注解
        TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class);
        //try method
        if (businessAction != null) {
            //save the xid 
            String xid = RootContext.getXID();
            //save the previous branchType
            BranchType previousBranchType = RootContext.getBranchType();
            //if not TCC, bind TCC branchType
            //将BranchType改变为TCC类型
            if (BranchType.TCC != previousBranchType) {
                RootContext.bindBranchType(BranchType.TCC);
            }
            try {
            	//获取方法的入参
                Object[] methodArgs = invocation.getArguments();
                //Handler the TCC Aspect
                //看这里
                Map<String, Object> ret = actionInterceptorHandler.proceed(method, methodArgs, xid, businessAction,
                        invocation::proceed);
                //return the final result
                //返回目标方法执行的结果
                return ret.get(Constants.TCC_METHOD_RESULT);
            }
            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();
}

public Map<String, Object> proceed(Method method, Object[] arguments, String xid, TwoPhaseBusinessAction businessAction,
                                       Callback<Object> targetCallback) throws Throwable {
        Map<String, Object> ret = new HashMap<>(4);

        //TCC name
        //获取注解的name属性
        String actionName = businessAction.name();
        //新建BusinessActionContext对象
        BusinessActionContext actionContext = new BusinessActionContext();
        //封装xid,actionName,branchId到actionContext 中
        actionContext.setXid(xid);
        //set action name
        actionContext.setActionName(actionName);

        //Creating Branch Record
        //看这里
        String branchId = doTccActionLogStore(method, arguments, businessAction, actionContext);
        actionContext.setBranchId(branchId);
        //MDC put branchId
        MDC.put(RootContext.MDC_KEY_BRANCH_ID, branchId);
		
        //set the parameter whose type is BusinessActionContext
        //判断我们方法中是否有BusinessActionContext类型的参数
        //如果有将actionContext赋值给方法的入参
        Class<?>[] types = method.getParameterTypes();
        int argIndex = 0;
        for (Class<?> cls : types) {
            if (cls.getName().equals(BusinessActionContext.class.getName())) {
                arguments[argIndex] = actionContext;
                break;
            }
            argIndex++;
        }
        //the final parameters of the try method
        ret.put(Constants.TCC_METHOD_ARGUMENTS, arguments);
        //the final result
        //执行目标方法,执行结果放入ret中 
        ret.put(Constants.TCC_METHOD_RESULT, targetCallback.execute());
        return ret;
}

protected String doTccActionLogStore(Method method, Object[] arguments, TwoPhaseBusinessAction businessAction,
                                         BusinessActionContext actionContext) {
        String actionName = actionContext.getActionName();
        String xid = actionContext.getXid();
        //解析BusinessActionContextParameter注解,设置方法参数到context中
        Map<String, Object> context = fetchActionRequestContext(method, arguments);
        context.put(Constants.ACTION_START_TIME, System.currentTimeMillis());
		
		//封装必要的TwoPhaseBusinessAction注解信息和当前调用的方法的方法名到context中
        //init business context
        initBusinessContext(context, method, businessAction);
        //Init running environment context
        //封装ip到context中
        initFrameworkContext(context);
        //解析后的方法入参(context)封装到actionContext中
        actionContext.setActionContext(context);

        //init applicationData
        Map<String, Object> applicationContext = new HashMap<>(4);
        applicationContext.put(Constants.TCC_ACTION_CONTEXT, context);
        String applicationContextStr = JSON.toJSONString(applicationContext);
        try {
        	//将context内容发送给seata服务端,获取branchId 
            //registry branch record
            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);
        }
}

protected Map<String, Object> fetchActionRequestContext(Method method, Object[] arguments) {
		//建立注解配置的name属性和参数的映射关系
        Map<String, Object> context = new HashMap<>(8);
		//获取方法参数的注解
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        for (int i = 0; i < parameterAnnotations.length; i++) {
            for (int j = 0; j < parameterAnnotations[i].length; j++) {
            	//如果方法参数含有@BusinessActionContextParameter注解
                if (parameterAnnotations[i][j] instanceof BusinessActionContextParameter) {
                	//获取注解信息
                    BusinessActionContextParameter param = (BusinessActionContextParameter)parameterAnnotations[i][j];
                    if (arguments[i] == null) {
                        throw new IllegalArgumentException("@BusinessActionContextParameter 's params can not null");
                    }
                    Object paramObject = arguments[i];
                    //默认为-1,可以配置大于0,用于从list中拿到指定位置的数据
                    int index = param.index();
                    //List, get by index
                    if (index >= 0) {
                        @SuppressWarnings("unchecked")
                        //强转为list
                        Object targetParam = ((List<Object>)paramObject).get(index);
                        //默认为false,配置为true,用于从对象中拿到某个属性
                        if (param.isParamInProperty()) {
                            //从对象中拿到属性值
                            context.putAll(ActionContextUtil.fetchContextFromObject(targetParam));
                        } else {
                            context.put(param.paramName(), targetParam);
                        }
                    } else {
                        if (param.isParamInProperty()) {
                            context.putAll(ActionContextUtil.fetchContextFromObject(paramObject));
                        } else {
                            context.put(param.paramName(), paramObject);
                        }
                    }
                }
            }
        }
        return context;
}

public static Map<String, Object> fetchContextFromObject(Object targetParam) {
        try {
        	//封装参数名称和参数
            Map<String, Object> context = new HashMap<>(8);
            List<Field> fields = new ArrayList<>();
            //获取类和父类的所有字段
            getAllField(targetParam.getClass(), fields);
			
			//循环遍历所有字段
            for (Field f : fields) {
                String fieldName = f.getName();
                BusinessActionContextParameter annotation = f.getAnnotation(BusinessActionContextParameter.class);
				//如果字段被BusinessActionContextParameter注解修饰
                if (annotation != null) {
                    f.setAccessible(true);
                    //获取到字段值
                    Object paramObject = f.get(targetParam);
                    //一样的逻辑,list取指定值 和 对象取属性值
                    int index = annotation.index();
                    if (annotation.isParamInProperty()) {
                        if (index >= 0) {
                            @SuppressWarnings("unchecked")
                            Object targetObject = ((List<Object>) paramObject).get(index);
                            context.putAll(fetchContextFromObject(targetObject));
                        } else {
                            context.putAll(fetchContextFromObject(paramObject));
                        }
                    } else {
                        if (StringUtils.isBlank(annotation.paramName())) {
                            context.put(fieldName, paramObject);
                        } else {
                            context.put(annotation.paramName(), paramObject);
                        }
                    }
                }
            }
            return context;
        } catch (Throwable t) {
            throw new FrameworkException(t, "fetchContextFromObject failover");
        }
}

  @GlobalTransaction注解相关的代码讲解AT的时候以及讲解过了,现在直接看到RM的接收commit和rollback请求的逻辑。

@Override
    public BranchStatus branchCommit(BranchType branchType, String xid, long branchId, String resourceId,
                                     String applicationData) throws TransactionException {
        //从tccResourceCache中使用resourceId获取到tccResource                  
        TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId);
        if (tccResource == null) {
            throw new ShouldNeverHappenException(String.format("TCC resource is not exist, resourceId: %s", resourceId));
        }
        //获取到bean和提交方法
        Object targetTCCBean = tccResource.getTargetBean();
        Method commitMethod = tccResource.getCommitMethod();
        if (targetTCCBean == null || commitMethod == null) {
            throw new ShouldNeverHappenException(String.format("TCC resource is not available, resourceId: %s", resourceId));
        }
        try {
            //BusinessActionContext
            //将服务端传递来的xid branchId resourceId applicationData(就是之前传过去applicationContextStr)
            BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId,
                applicationData);
            //反射调用提交方法
            Object ret = commitMethod.invoke(targetTCCBean, businessActionContext);
            LOGGER.info("TCC resource commit result : {}, xid: {}, branchId: {}, resourceId: {}", ret, xid, branchId, resourceId);
            boolean result;
            //方法有返回结果
            if (ret != null) {
            	//如果返回结果是TwoPhaseResult类型
                if (ret instanceof TwoPhaseResult) {
                    result = ((TwoPhaseResult)ret).isSuccess();
                } else {
                	//强转为boolean
                    result = (boolean)ret;
                }
            } else {
            	//方法没有返回值,则result 为true
                result = true;
            }
            //方法返回结果为false,则返回提交重试给seata服务端,seata服务端会再次向RM发送提交请求。
            //返回true,则返回已经提交给seata服务端。
            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);
            //方法调用发生异常,返回重试给seata服务端,seata服务端会再次向RM发送提交请求
            return BranchStatus.PhaseTwo_CommitFailed_Retryable;
        }
    }

  回滚和提交可以说是一毛一样了,只是调用的是注解配置的回滚方法,返回给seata服务端的状态码不一样。

public BranchStatus branchRollback(BranchType branchType, String xid, long branchId, String resourceId,
                                       String applicationData) throws TransactionException {
                                     
        TCCResource tccResource = (TCCResource)tccResourceCache.get(resourceId);
        if (tccResource == null) {
            throw new ShouldNeverHappenException(String.format("TCC resource is not exist, resourceId: %s", resourceId));
        }
        Object targetTCCBean = tccResource.getTargetBean();
        Method rollbackMethod = tccResource.getRollbackMethod();
        if (targetTCCBean == null || rollbackMethod == null) {
            throw new ShouldNeverHappenException(String.format("TCC resource is not available, resourceId: %s", resourceId));
        }
        try {
            //BusinessActionContext
            BusinessActionContext businessActionContext = getBusinessActionContext(xid, branchId, resourceId,
                applicationData);
            Object ret = rollbackMethod.invoke(targetTCCBean, businessActionContext);
            LOGGER.info("TCC resource rollback result : {}, xid: {}, branchId: {}, resourceId: {}", ret, xid, branchId, resourceId);
            boolean result;
            if (ret != null) {
                if (ret instanceof TwoPhaseResult) {
                    result = ((TwoPhaseResult)ret).isSuccess();
                } else {
                    result = (boolean)ret;
                }
            } else {
                result = true;
            }
            return result ? BranchStatus.PhaseTwo_Rollbacked : BranchStatus.PhaseTwo_RollbackFailed_Retryable;
        } catch (Throwable t) {
            String msg = String.format("rollback TCC resource error, resourceId: %s, xid: %s.", resourceId, xid);
            LOGGER.error(msg, t);
            return BranchStatus.PhaseTwo_RollbackFailed_Retryable;
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值