今天我们进行seata分布式事务TCC模式的源码分析:
首先其TCC源码和AT模式的源码基本都在一起,只是稍微有一些不同的地方,因此我们碰到以前详细分析过的地方就简单提一下,且TCC 的 TM 的源码跟 AT 是一样的,这里就不做分析了,下面我们就开始吧!
1、于是从这里开始:
2、根据策略模式判断是否TCC: TCCBeanParserUtils.isTccAutoProxy 方法进入
public static boolean isTccAutoProxy(Object bean, String beanName, ApplicationContext applicationContext) { boolean isRemotingBean = parserRemotingServiceInfo(bean, beanName); //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); } 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); } } }
3、进入 parserRemotingServiceInfo(bean, beanName);方法:
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; } return false; }
4、进入 parserRemotingServiceInfo 方法:
public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, RemotingParser remotingParser) { RemotingDesc remotingBeanDesc = remotingParser.getServiceDesc(bean, beanName); if (remotingBeanDesc == null) { return null; } remotingServiceMap.put(beanName, remotingBeanDesc); Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass(); Method[] methods = interfaceClass.getMethods(); if (remotingParser.isService(bean, beanName)) { try { //service bean, registry resource Object targetBean = remotingBeanDesc.getTargetBean(); for (Method m : methods) { TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class); if (twoPhaseBusinessAction != null) { TCCResource tccResource = new TCCResource(); 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 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; } 5、进入 remotingParser.getServiceDesc(bean, beanName);方法:
6、进入LocalTCCRemotingParser 解析器类:
@Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { if (!this.isRemoting(bean, beanName)) { return null; } RemotingDesc remotingDesc = new RemotingDesc(); remotingDesc.setReference(true); remotingDesc.setProtocol(Protocols.IN_JVM); Class<?> classType = bean.getClass(); Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType); for (Class<?> interClass : interfaceClasses) { if (interClass.isAnnotationPresent(LocalTCC.class)) { remotingDesc.setInterfaceClassName(interClass.getName()); remotingDesc.setInterfaceClass(interClass); remotingDesc.setTargetBean(bean); return remotingDesc; } } throw new FrameworkException("Couldn't parser any Remoting info"); } 7、进入isService(bean, beanName) 方法:
8、进入 LocalTCCRemotingParser 解析器类:
@Override public boolean isService(Object bean, String beanName) { Class<?> classType = bean.getClass(); Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType); for (Class<?> interClass : interfaceClasses) { if (interClass.isAnnotationPresent(LocalTCC.class)) { return true; } } return false; }
9、进入 isTccProxyTargetBean(remotingDesc);方法:
protected static boolean isTccProxyTargetBean(RemotingDesc remotingDesc) { if (remotingDesc == null) { return false; } //check if it is TCC bean boolean isTccClazz = false; Class<?> tccInterfaceClazz = remotingDesc.getInterfaceClass(); Method[] methods = tccInterfaceClazz.getMethods(); TwoPhaseBusinessAction twoPhaseBusinessAction; for (Method method : methods) { twoPhaseBusinessAction = method.getAnnotation(TwoPhaseBusinessAction.class); if (twoPhaseBusinessAction != null) { isTccClazz = true; break; } } if (!isTccClazz) { return false; } short protocols = remotingDesc.getProtocol(); //LocalTCC if (Protocols.IN_JVM == protocols) { //in jvm TCC bean , AOP return true; } // sofa:reference / dubbo:reference, AOP return remotingDesc.isReference(); }
10、点击 TccActionInterceptor 类:
public TccActionInterceptor(RemotingDesc remotingDesc) { this.remotingDesc = remotingDesc; } @Override public Object invoke(final MethodInvocation invocation) throws Throwable { if (!RootContext.inGlobalTransaction()) { //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(); //clear the context RootContext.unbind(); RootContext.bindInterceptorType(xid, BranchType.TCC); try { Object[] methodArgs = invocation.getArguments(); //Handler the TCC Aspect //跟 TC 通讯,注册 RM,把二阶段的 commit 和 rollback 方法名称传给 TC Map<String, Object> ret = actionInterceptorHandler.proceed(method, methodArgs, xid, businessAction, invocation::proceed);//火炬传递,调用被代理方法,执行业务逻辑 //return the final result return ret.get(Constants.TCC_METHOD_RESULT); } finally { //recovery the context RootContext.unbindInterceptorType(); RootContext.bind(xid); } } return invocation.proceed(); }
11、点击 actionInterceptorHandler.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 String actionName = businessAction.name(); BusinessActionContext actionContext = new BusinessActionContext(); actionContext.setXid(xid); //set action anme actionContext.setActionName(actionName); //Creating Branch Record 远程调用通知TC String branchId = doTccActionLogStore(method, arguments, businessAction, actionContext); actionContext.setBranchId(branchId); //set the parameter whose type is BusinessActionContext 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.put(Constants.TCC_METHOD_RESULT, targetCallback.execute()); return ret; }
12、点击 doTccActionLogStore 方法:
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()); //init business context 核心 initBusinessContext(context, method, businessAction); //Init running environment context initFrameworkContext(context); 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 { //registry branch record 和TC通信 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); } } 13、点击fetchActionRequestContext方法:
protected Map<String, Object> fetchActionRequestContext(Method method, Object[] arguments) { 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++) { if (parameterAnnotations[i][j] instanceof BusinessActionContextParameter) { BusinessActionContextParameter param = (BusinessActionContextParameter)parameterAnnotations[i][j]; if (null == arguments[i]) { throw new IllegalArgumentException("@BusinessActionContextParameter 's params can not null"); } Object paramObject = arguments[i]; int index = param.index(); //List, get by index if (index >= 0) { @SuppressWarnings("unchecked") Object targetParam = ((List<Object>)paramObject).get(index); 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; }
14、点击 initBusinessContext方法:
protected void initBusinessContext(Map<String, Object> context, Method method, TwoPhaseBusinessAction businessAction) { if (method != null) { //the phase one method name context.put(Constants.PREPARE_METHOD, method.getName()); } if (businessAction != null) { //the phase two method name context.put(Constants.COMMIT_METHOD, businessAction.commitMethod()); context.put(Constants.ROLLBACK_METHOD, businessAction.rollbackMethod()); context.put(Constants.ACTION_NAME, businessAction.name()); } }
15、这是TCC一阶段提交的提交的流程,正式提交和回滚思路和也是和AT模式类似的,大家可以试着查看一下。
这里也可以看到,TCC 模式的 RM 的代理主要就是注册了 RM,封 BusinessActionContext 对象传递给 TC,TC 二阶段回调的时候又把 BusinessActionContext 对象传递回 RM,所以就感觉一阶段和二阶段方法共享了 BusinessActionContext 对象的错 觉。
到此结束,下篇我们分析sage模式的使用,敬请期待!