TCC-transaction源码(一):Compensable注解和事务拦截器

一 、Compensable注解的两个切面

@Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable)")
  1. org.mengyun.tcctransaction.spring.ConfigurableTransactionAspect

    顺序 Ordered.HIGHEST_PRECEDENCE;

  2. org.mengyun.tcctransaction.interceptor.ResourceCoordinatorAspect

    顺序Ordered.HIGHEST_PRECEDENCE + 1;

ConfigurableTransactionAspect负责管理事务,包括开启事务;

ResourceCoordinatorAspect负责协调事务参与者,包括创建参与者列表等。

二、 事务管理拦截器org.mengyun.tcctransaction.interceptor.CompensableTransactionInterceptor

  1. 看看事务拦截器做了什么
public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
    CompensableMethodContext compensableMethodContext = new CompensableMethodContext(pjp);
	// 判断当前线程是否已经创建事务
    boolean isTransactionActive = transactionManager.isTransactionActive();
	// 校验事务传播属性为mandatory时,当前必须要有事务,否则报错
    if (!TransactionUtils.isLegalTransactionContext(isTransactionActive, compensableMethodContext)) {
        throw new SystemException("no active compensable transaction while propagation is mandatory for method " + compensableMethodContext.getMethod().getName());
    }
	// 注释在下面
    switch (compensableMethodContext.getMethodRole(isTransactionActive)) {
        case ROOT:
            return rootMethodProceed(compensableMethodContext);
        case PROVIDER:
            return providerMethodProceed(compensableMethodContext);
        default:
            return pjp.proceed();
    }
}
  1. 事务拦截其中判断方法类型的方法
/**
     * getMethodRole方法中的逻辑是:
     * 1. 如果需要分布式事务,当前线程还没有创建事务,事务上下文为空,那么这就是一个根事务ROOT; 
     * 2. 如果需要分布式事务,当前线程还没有创建事务,但是事务上下文不为空,这种情况事务上下文是作为参        * 数传过来的,此时就是个参与事务的分支服务的方法,类型为PROVIDER;
     * 3. 否则的话就是个普通方法,类型为NORMAL
     */
public MethodRole getMethodRole(boolean isTransactionActive) {
    if ((propagation.equals(Propagation.REQUIRED) && !isTransactionActive && transactionContext == null) ||
            propagation.equals(Propagation.REQUIRES_NEW)) {
        return MethodRole.ROOT;
    } else if ((propagation.equals(Propagation.REQUIRED) || propagation.equals(Propagation.MANDATORY)) && !isTransactionActive && transactionContext != null) {
        return MethodRole.PROVIDER;
    } else {
        return MethodRole.NORMAL;
    }
}
  1. 如果是根事务方法,这样执行
private Object rootMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {

    Object returnValue = null;
    Transaction transaction = null;
    // 获取注解中异步确认和异步取消的配置
    boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
    boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();
	// 设置哪些异常情况下,不直接执行回滚方法,比如超时异常等,此时服务提供方不一定失败了,可能在调用超过之后还会正确的返回
    Set<Class<? extends Exception>> allDelayCancelExceptions = new HashSet<Class<? extends Exception>>();
    allDelayCancelExceptions.addAll(this.delayCancelExceptions);
   allDelayCancelExceptions.addAll(Arrays.asList(compensableMethodContext.getAnnotation().delayCancelExceptions()));

    try {
		// 开启一个事务
        transaction = transactionManager.begin(compensableMethodContext.getUniqueIdentity());

        try {
            // 真正执行业务方法
            returnValue = compensableMethodContext.proceed();
        } catch (Throwable tryingException) {
			// 如果执行业务try方法抛出了异常,并且不是延迟回复你的异常的时候,直接回滚
            if (!isDelayCancelException(tryingException, allDelayCancelExceptions)) {

                logger.warn(String.format("compensable transaction trying failed. transaction content:%s", JSON.toJSONString(transaction)), tryingException);

                transactionManager.rollback(asyncCancel);
            }

            throw tryingException;
        }
		// 如果try方法没有异常,提交事务
        transactionManager.commit(asyncConfirm);

    } finally {
        // try方法执行结束后清理资源
        transactionManager.cleanAfterCompletion(transaction);
    }

    return returnValue;
}
  • 其中begin方法
public Transaction begin(Object uniqueIdentify) {
    /** 创建一个事务,如果没有通过UniqueIdentity注解设置事务唯一id,通过uuid生成一个,事务类型是
     * TransactionType.ROOT,事务状态是TRYING
     */
    Transaction transaction = new Transaction(uniqueIdentify,TransactionType.ROOT);
    // 把事务记录到TCC库的表里,存了哪些字段等具体可以到JdbcTransactionRepository里看
    transactionRepository.create(transaction);
    // 事务记录到当前线程的事务队列汇总
    registerTransaction(transaction);
    return transaction;
}
  • commit方法
/**
 * 逐个调用所有事务参与者的确认方法
 */
public void commit() {
    for (Participant participant : participants) {
        participant.commit();
    }
}
public void commit() {
    Terminator.invoke(new TransactionContext(xid, TransactionStatus.CONFIRMING.getId()), confirmInvocationContext, transactionContextEditorClass);
}
  • rollback方法
/**
 * 逐个调用所有事务参与者的取消方法
 */
public void rollback() {
    for (Participant participant : participants) {
        participant.rollback();
    }
}
public void rollback() {
    Terminator.invoke(new TransactionContext(xid, TransactionStatus.CANCELLING.getId()), cancelInvocationContext, transactionContextEditorClass);
}
  • begin方法
public Transaction begin(Object uniqueIdentify) {
    /** 创建一个事务,如果没有通过UniqueIdentity注解设置事务唯一id,通过uuid生成一个,事务类型是
     * TransactionType.ROOT,事务状态是TRYING
     */
    Transaction transaction = new Transaction(uniqueIdentify,TransactionType.ROOT);
    // 把事务记录到TCC库的表里,存了哪些字段等具体可以到JdbcTransactionRepository里看
    transactionRepository.create(transaction);
    // 事务记录到当前线程的事务队列汇总
    registerTransaction(transaction);
    return transaction;
}
  1. 如果是分支事务的方法,这样执行
private Object providerMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {

    Transaction transaction = null;
    boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
    boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();

    try {
        switch (TransactionStatus.valueOf(compensableMethodContext.getTransactionContext().getStatus())) {
            case TRYING:
                // 如果事务状态是TRYING,创建分支事务,事务id是事务上下文中获取到的,类型是BRANCH,状态是TRYING,然后执行业务方法
                transaction = transactionManager.propagationNewBegin(compensableMethodContext.getTransactionContext());
                return compensableMethodContext.proceed();
            case CONFIRMING:
                try {
                    // 如果事务状态是CONFIRMING,根据事务id更新TCC库中事务的状态为CONFIRMING,然后提交事务
                    transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());
                    transactionManager.commit(asyncConfirm);
                } catch (NoExistedTransactionException excepton) {
                    //the transaction has been commit,ignore it.
                }
                break;
            case CANCELLING:

                try {
                    // 如果事务状态是CANCELLING,根据事务id更新TCC库中事务的状态为CANCELLING,然后回滚事务
                    transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());
                    transactionManager.rollback(asyncCancel);
                } catch (NoExistedTransactionException exception) {
                    //the transaction has been rollback,ignore it.
                }
                break;
        }

    } finally {
        transactionManager.cleanAfterCompletion(transaction);
    }
	// 能走到这里上面case里的流程都失败了,返回默认值
    Method method = compensableMethodContext.getMethod();
    return ReflectionUtils.getNullValue(method.getReturnType());
}

三、资源(事务参与者)协调拦截器org.mengyun.tcctransaction.interceptor.ResourceCoordinatorInterceptor

  1. 看看拦截器做了什么
public Object interceptTransactionContextMethod(ProceedingJoinPoint pjp) throws Throwable {
	// 获取当前线程事务
    Transaction transaction = transactionManager.getCurrentTransaction();
	// 如果事务不为空(已经在事务管理切面创建过了)
    if (transaction != null) {
		// 事务是trying阶段的时候,加入到事务参与者列表,其他阶段直接执行
        switch (transaction.getStatus()) {
            case TRYING:
                enlistParticipant(pjp);
                break;
            case CONFIRMING:
                break;
            case CANCELLING:
                break;
        }
    }
    return pjp.proceed(pjp.getArgs());
}
  1. 只有在try阶段,才加入事务参与者队列
private void enlistParticipant(ProceedingJoinPoint pjp) throws IllegalAccessException, InstantiationException {
	// 获取事务注解的方法
    Method method = CompensableMethodUtils.getCompensableMethod(pjp);
    if (method == null) {
        throw new RuntimeException(String.format("join point not found method, point is : %s", pjp.getSignature().getName()));
    }
    // 从方法的注解里面提取出来确认方法和取消方法
    Compensable compensable = method.getAnnotation(Compensable.class);
    String confirmMethodName = compensable.confirmMethod();
    String cancelMethodName = compensable.cancelMethod();
	// 获取当前事务和事务id
    Transaction transaction = transactionManager.getCurrentTransaction();
    TransactionXid xid = new TransactionXid(transaction.getXid().getGlobalTransactionId());
    /**
     * 遍历try方法所有参数,如果没有TransactionContext类型的参数,则
     * 
     */
    if (FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().get(pjp.getTarget(), method, pjp.getArgs()) == null) {
        FactoryBuilder.factoryOf(compensable.transactionContextEditor()).getInstance().set(new TransactionContext(xid, TransactionStatus.TRYING.getId()), pjp.getTarget(), ((MethodSignature) pjp.getSignature()).getMethod(), pjp.getArgs());
    }
	// 获取事务注解拦截的类
    Class targetClass = ReflectionUtils.getDeclaringType(pjp.getTarget().getClass(), method.getName(), method.getParameterTypes());
	// 把类、确认方法(取消方法)、方法参数类型、参数值构造成方法调用封装类
    InvocationContext confirmInvocation = new InvocationContext(targetClass,
            confirmMethodName,
            method.getParameterTypes(), pjp.getArgs());

    InvocationContext cancelInvocation = new InvocationContext(targetClass,
            cancelMethodName,
            method.getParameterTypes(), pjp.getArgs());
	// 把事务id、调用方法封装、取消方法封装、事务上下文组装成一个参与者
    Participant participant =
            new Participant(
                    xid,
                    confirmInvocation,
                    cancelInvocation,
                    compensable.transactionContextEditor());
	// 把事务参与者加入到事务管理器的参与者列表
    transactionManager.enlistParticipant(participant);

}
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页