前文已经讲解了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;
}
}