三TCC-transaction分布式事务关键组件--2事务拦截器

三 TCC-transaction分布式事务关键组件--2事务拦截器

2.2.3 事务拦截器

TCC有两个拦截器:

CompensableTransactionInterceptor:可补偿事务拦截器
  用于tcc事务的流程执行begin(try)、commit(confirm)、rollback(cancel)
  
ResourceCoordinatorInterceptor:资源协调拦截器
	用于记录tcc事务的Participant(参与方)

image-20230518123536314

这两个拦截器,例如ResourceCoordinatorInterceptor,其基于@Compensable注解在try方法上、@Aspect注解在aspect类上作为切面类,能够拦截事务的try方法。在参与者的try方法前后是around切面逻辑,拦截器在try目标方法执行前后,分别调用两个拦截器内的方法,实现TCC事务的透明化执行过程。

@Aspect
public abstract class ResourceCoordinatorAspect {

    private ResourceCoordinatorInterceptor resourceCoordinatorInterceptor = new ResourceCoordinatorInterceptor();

    @Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable) || @annotation(org.mengyun.tcctransaction.api.EnableTcc)")
    public void transactionResourcePointcut() {

    }

    @Around("transactionResourcePointcut()")
    public Object interceptTransactionResourceMethodWithCompensableAnnotation(ProceedingJoinPoint pjp) throws Throwable {

        Method method = ((MethodSignature) pjp.getSignature()).getMethod();

        Compensable compensable = method.getAnnotation(Compensable.class);

        return interceptTransactionContextMethod(new AspectJTransactionMethodJoinPoint(pjp, compensable, ThreadLocalTransactionContextEditor.class));
    }

0 @Compensable注解

该注解标注在参与者的try方法上,并指定cancel/confirm方法名、事务的传播级别

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Compensable {
		//指定事务传播级别	
    public Propagation propagation() default Propagation.REQUIRED;
		//指定cc方法
    public String confirmMethod() default "";
    public String cancelMethod() default "";
		//是否异步执行
    public boolean asyncConfirm() default false;
    public boolean asyncCancel() default false;
}

传播级别定义:

public enum Propagation {
    /**
 * 支持当前事务,如果当前没有事务,就新建一个事务。
 */
REQUIRED(0),
/**
 * 支持当前事务,如果当前没有事务,就以非事务方式执行。
 */
SUPPORTS(1),
/**
 * 支持当前事务,如果当前没有事务,就抛出异常。
 */
MANDATORY(2),
/**
 * 新建事务,如果当前存在事务,把当前事务挂起。
 */
REQUIRES_NEW(3);

1 CompensableTransactionInterceptor可补偿事务拦截器

image-20230518170037586

用于tcc事务的流程执行begin(try)、commit(confirm)、rollback(cancel)

image-20230518142342941

(1)CompensableTransactionAspect切面类
//配置当前类为aspect切面类(springAOP)
@Aspect
public abstract class CompensableTransactionAspect {

  	//切面类内对目标方法拦截,需要调用拦截器执行具体的TCC框架逻辑
    private CompensableTransactionInterceptor compensableTransactionInterceptor = new CompensableTransactionInterceptor();

  //设置拦截器内的TransactionManager
    public void setTransactionManager(TransactionManager transactionManager) {
        this.compensableTransactionInterceptor.setTransactionManager(transactionManager);
    }
//配置@Compensable标注的方法为切点
    @Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable)")
    public void compensableTransactionPointcut() {

    }

  //在切点处,配置around环绕执行的逻辑
    @Around("compensableTransactionPointcut()")
    public Object interceptCompensableMethod(ProceedingJoinPoint pjp) throws Throwable {
				//获取@Compensable注解的方法对象
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();

        Compensable compensable = method.getAnnotation(Compensable.class);
				
      
        return compensableTransactionInterceptor.interceptCompensableMethod(new AspectJTransactionMethodJoinPoint(pjp, compensable, ThreadLocalTransactionContextEditor.class));
    }

  //获取当前切面执行的优先级
    public abstract int getOrder();
}
(2)ConfigurableTransactionAspect 切面配置类(执行优先级)
@Aspect
public class ConfigurableTransactionAspect extends CompensableTransactionAspect implements Ordered {

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE; //指定当前切面的优先级
    }

    @Autowired
    public void setTransactionManager(TransactionManagerFactory transactionManagerFactory) {
        super.setTransactionManager(transactionManagerFactory.getTransactionManager());
    }
}

当前切面配置类,主要是实现orderde接口,定义切面的优先级Ordered.HIGHEST_PRECEDENCE(ResourceCoordinatorInterceptor配置的优先级为Ordered.HIGHEST_PRECEDENCE+1,所以执行时,位于后面,先执行CompensableTransactionAspect)

(3)CompensableTransactionInterceptor拦截器
public class CompensableTransactionInterceptor {
		//拦截器中持有transactionManager
    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public Object interceptCompensableMethod(TransactionMethodJoinPoint pjp) throws Throwable {
				//获取当前transactionManager的本地线程变量上事务队列的首部transaction
        Transaction transaction = transactionManager.getCurrentTransaction();
      //创建可补偿方法执行上下文对象
        CompensableMethodContext compensableMethodContext = new CompensableMethodContext(pjp, transaction);
				
    //如果方法被@Compensable注解&transaction context为null&transaction对象为null,那么ParticipantRole为ROOT根角色
		//如果方法被@Compensable注解&transaction context存在&transaction对象为null,那么表示已经创建transaction context事务上下文,此时ParticipantRole的为privider提供者角色
      //TAG1 compensableMethodContext.getParticipantRole()
        switch (compensableMethodContext.getParticipantRole()) {
            case ROOT: //执行root根事务方法
            //TAG2 rootMethodProceed
                return rootMethodProceed(compensableMethodContext);
            case PROVIDER: //执行provider提供者事务方法
            //TAG3 providerMethodProceed
                return providerMethodProceed(compensableMethodContext);
            default: //默认不处理,继续目标方法try的执行
                return compensableMethodContext.proceed();
        }
    }

这里,CompensableTransactionInterceptor拦截器,在被@Compensable标注的try方法执行时,通过切面类拦截,然后调用此处拦截器方法:

1 获取当前transactionManager的本地线程变量上事务队列的首部transaction;
2 创建CompensableMethodContext;
3 根据TCC方法上下文,判断当前参与者的角色,是ROOT(事务发起者)还是PROVIDER(分支事务的参与者)------根据不同参与者类型,执行不同的事务处理
TAG1 compensableMethodContext.getParticipantRole()

该方法,是通过transactionContext、compensable、transaction三个对象的存在情况,判断当前参与者的角色--是ROOT发起根事务的角色、还是PRIVIDER分支事务参与者的角色。

判断参与者角色是ROOT还是PROVIDER原则:

		//如果方法被@Compensable注解&transaction context为null&transaction对象为null,那么ParticipantRole为ROOT根角色
		//如果方法被@Compensable注解&transaction context存在&transaction对象为null,那么表示已经创建transaction context事务上下文,此时ParticipantRole的为privider提供者角色
public class CompensableMethodContext {

  //事务方法连结点(具体详看spring部分)
    TransactionMethodJoinPoint pjp = null;
    TransactionContext transactionContext = null;
    Compensable compensable = null;
    private Transaction transaction = null;
    
        public ParticipantRole getParticipantRole() {

  // 1 如果方法是@Compensable注释的,则表示需要tcc事务,如果没有活动事务,则需要require new。
	// 2 If方法没有@Compensable注解,但TransactionContext存在:
		//2.1如果有活动事务,则表示需要参与者tcc事务。如果transactionContext为空,那么它将事务登记为CONSUMER角色;
		// 2.2 如果没有活动事务activeTransaction,表示有另一个方法被调用,因为Consumer已经登记为了事务,这个方法不需要登记为参与者。


        //如果方法被@Compensable注解&transaction context为null&transaction对象为null,那么ParticipantRole为ROOT根角色
        if (compensable != null && transaction == null && transactionContext == null) {
            return ParticipantRole.ROOT;
        }

       //如果方法被@Compensable注解&transaction context存在&transaction对象为null,那么表示已经创建transaction context事务上下文,此时ParticipantRole的为privider提供者角色
        if (compensable != null && transaction == null && transactionContext != null) {
            return ParticipantRole.PROVIDER;
        }
			
          //不进行事务处理
        return ParticipantRole.NORMAL;
    }

    public Object proceed() throws Throwable {
        return this.pjp.proceed();
    }
TAG2 rootMethodProceed发起TCC流程

当ParticipantRole为ROOT时,发起根事务,开启TCC流程:

   private Object rootMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {

        Object returnValue = null;
				//事务对象
        Transaction transaction = null;
				//是否异步执行confirm/cancel
        boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
        boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();

        try {
            //发起根root事务
            transaction = transactionManager.begin(compensableMethodContext.getUniqueIdentity());

            try {
                //执行方法原逻辑,即try逻辑
                returnValue = compensableMethodContext.proceed();
            } catch (Throwable tryingException) {

                try {
                    //当原逻辑执行失败时,即try阶段失败---回滚
                    transactionManager.rollback(asyncCancel);
                } catch (Exception rollbackException) {
                    logger.warn("compensable transaction rollback failed, recovery job will try to rollback later", rollbackException);
                }

                throw tryingException;
            }
            //当原逻辑执行成功时,即try阶段成功,提交事务
            transactionManager.commit(asyncConfirm);

        } finally {
            //将事物从当前线程事务队列移除
            transactionManager.cleanAfterCompletion(transaction);
        }

        return returnValue;
    }

主要逻辑:

1 transactionManager.begin发起根事务;
2 compensableMethodContext.proceed()执行try;
	2.1 如果try失败抛异常,transactionManager.rollback(asyncCancel)回滚
3  transactionManager.commit(asyncConfirm) try执行成功,commit提交事务;
4 transactionManager.cleanAfterCompletion(transaction)将transaction从事务管理器transactionManager的本地线程变量的事务队列中移除;
5 返回结果;
TAG3 providerMethodProceed服务提供者参与TCC流程

当参与者角色为PROVIDER时,执行该方法:(ROOT是发起事务,在TCC三个阶段开始前,所以不需要通过compensableMethodContext.getTransactionContext().getStatus()判断当前所处的阶段;但是PROVIDER角色时,参与者参与事务,因此需要知道自己当前处于当前事务的哪个阶段执行过程TRYING、CONFIRMING、CANCELLING。

   private Object providerMethodProceed(CompensableMethodContext compensableMethodContext) throws Throwable {

        Transaction transaction = null;
				//是否异步执行cc
        boolean asyncConfirm = compensableMethodContext.getAnnotation().asyncConfirm();
        boolean asyncCancel = compensableMethodContext.getAnnotation().asyncCancel();

        try {
		//获取TransactionContext().getStatus()中,当前TCC执行的阶段
            switch (compensableMethodContext.getTransactionContext().getStatus()) {
/** ……………………………………………………………………………………………………TRYING………………………………………………………………………………………………………………*/
                case TRYING:
           //如果trying阶段,需要propagationNewBegin传播并发起分支事务(包括创建transaction、存储、注册)
                    transaction = transactionManager.propagationNewBegin(compensableMethodContext.getTransactionContext());

                    Object result = null;

                    try {
                        //执行原try逻辑
                        result = compensableMethodContext.proceed();
                      //设置transactionManager上事务队列首个事务状态TRY_SUCCESS,并在数据库中更新
                        transactionManager.changeStatus(TransactionStatus.TRY_SUCCESS);
                    } catch (Throwable e) {
                        try {
                        //如果try执行失败,设置transactionManager上事务队列首个事务状态为TRY_FAILED,并更新数据库中数据
                            transactionManager.changeStatus(TransactionStatus.TRY_FAILED);
                        } catch (Exception ignore) {
                            //ignore
                        }
                        throw e;
                    }

                    return result;

/** ……………………………………………………………………………………………………CONFIRMING………………………………………………………………………………………………………………*/
                case CONFIRMING:
                    try {
                        //获取传播分支事务
                        transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());
                      //执行提交
                        transactionManager.commit(asyncConfirm);
                    } catch (NoExistedTransactionException excepton) {
                        //the transaction has been commit,ignore it.
                        logger.warn("no existed transaction found at CONFIRMING stage, will ignore and confirm automatically. transaction xid:{}", compensableMethodContext.getTransactionContext().getXid());
                    }
                    break;
                
/** ……………………………………………………………………………………………………CANCELLING………………………………………………………………………………………………………………*/
                case CANCELLING:
                    try {
                        //从消费者端传递过来的,分支事务branch的状态status
                        ParticipantStatus transactionStatusFromConsumer = compensableMethodContext.getTransactionContext().getParticipantStatus();

                        //获取传播分支事务
                        transaction = transactionManager.propagationExistBegin(compensableMethodContext.getTransactionContext());

  // 1 只有transaction's status 处于TRY_SUCCESS、TRY_FAILED、CANCELLING stage,才能rollback(表示第一阶段的try执行结束,所以,单纯的trying状态,是不能够rollback的)
  // 2 如果 transactionStatusFromConsumer 是TRY_SUCCESS,也表示第一阶段try执行结束, 无论当前transaction的状态是否是trying,都可以rollback
    // (原因:transaction's status is TRYING while transactionStatusFromConsumer is TRY_SUCCESS 可能会发生的,就是当 transaction's changeStatus 是异步执行时.)
                        if (transaction.getStatus().equals(TransactionStatus.TRY_SUCCESS)
                                || transaction.getStatus().equals(TransactionStatus.TRY_FAILED)
                                || transaction.getStatus().equals(TransactionStatus.CANCELLING)
                                || ParticipantStatus.TRY_SUCCESS.equals(transactionStatusFromConsumer)) {
                            transactionManager.rollback(asyncCancel);
                        } else {
                            //in this case, transaction's Status is TRYING and transactionStatusFromConsumer is TRY_FAILED
                            // this may happen if timeout exception throws during rpc call.
                            throw new IllegalTransactionStatusException("Branch transaction status is TRYING, cannot rollback directly, waiting for recovery job to rollback.");
                        }

                    } catch (NoExistedTransactionException exception) {
                        //the transaction has been rollback,ignore it.
                        logger.info("no existed transaction found at CANCELLING stage, will ignore and cancel automatically. transaction xid:{}", compensableMethodContext.getTransactionContext().getXid());
                    }
                    break;
            }

        } finally {
          //清理当前事务对象
            transactionManager.cleanAfterCompletion(transaction);
        }

        Method method = compensableMethodContext.getMethod();

        return ReflectionUtils.getNullValue(method.getReturnType());
    }

对于服务提供者provider,在事务执行过程的逻辑如下:

 switch (compensableMethodContext.getTransactionContext().getStatus()) {
     
 TRYING:
 	1 propagationNewBegin传播并发起分支事务------该方法调用前提:TransactionStatus.TRYING&ParticipantRole.PROVIDER;
  2 compensableMethodContext.proceed()执行try方法逻辑;
  3 transactionManager.changeStatus(TransactionStatus.TRY_SUCCESS) try成功,修改transaction状态,并update持久存储内;
    2.1 如果try失败,transactionManager.changeStatus(TransactionStatus.TRY_FAILED),修改transaction状态,并update;
  4 return;

 CONFIRMING:
 1 propagationExistBegin传播并获取分支事务------该方法调用前提:TransactionStatus.CONFIRMING&ParticipantRole.PROVIDER;
 2 transactionManager.commit(asyncConfirm)提交;
   (confirm失败的逻辑,在transactionManager中,会update更新transaction)
   
 CANCELLING:
  1 propagationExistBegin传播并获取分支事务------该方法调用前提:TransactionStatus.CANCELLING&ParticipantRole.PROVIDER;
  2 可以执行rollback的条件和情况如下: 
    // 1 只有transaction's status 处于TRY_SUCCESS、TRY_FAILED、CANCELLING stage,才能rollback(表示第一阶段的try执行结束,所以,单纯的trying状态,是不能够rollback的)
  // 2 如果 transactionStatusFromConsumer 是TRY_SUCCESS,也表示第一阶段try执行结束, 无论当前transaction的状态是否是trying,都可以rollback
    // (原因:transaction's status is TRYING while transactionStatusFromConsumer is TRY_SUCCESS 可能会发生的,就是当 transaction's changeStatus 是异步执行时.)
    
    finally{
      transactionManager.cleanAfterCompletion(transaction);清理事务
    }

2 ResourceCoordinatorInterceptor资源协调拦截器

image-20230518170044224

用于记录tcc事务的Participant(参与方),ResourceCoordinatorInterceptor只在try阶段使用,负责participant的创建、添加入transaction、pjp.proceed执行try方法、根据try执行是否成功设置participant的执行状态。负责参与者的管理。

image-20230518165950876

(1)ResourceCoordinatorAspect 切面类
@Aspect
public abstract class ResourceCoordinatorAspect {

    private ResourceCoordinatorInterceptor resourceCoordinatorInterceptor = new ResourceCoordinatorInterceptor();

    @Pointcut("@annotation(org.mengyun.tcctransaction.api.Compensable) || @annotation(org.mengyun.tcctransaction.api.EnableTcc)")
    public void transactionResourcePointcut() {

    }

    @Around("transactionResourcePointcut()")
    public Object interceptTransactionResourceMethodWithCompensableAnnotation(ProceedingJoinPoint pjp) throws Throwable {

        Method method = ((MethodSignature) pjp.getSignature()).getMethod();

        Compensable compensable = method.getAnnotation(Compensable.class);

        return interceptTransactionContextMethod(new AspectJTransactionMethodJoinPoint(pjp, compensable, ThreadLocalTransactionContextEditor.class));
    }

    public Object interceptTransactionContextMethod(TransactionMethodJoinPoint pjp) throws Throwable {
        return resourceCoordinatorInterceptor.interceptTransactionContextMethod(pjp);
    }

    public void setTransactionManager(TransactionManager transactionManager) {
        this.resourceCoordinatorInterceptor.setTransactionManager(transactionManager);
    }

    public abstract int getOrder();
}

具体分析和可补偿事务拦截器相同,省略。

(2)ConfigurableCoordinatorAspect切面配置类(执行优先级)
@Aspect
public class ConfigurableCoordinatorAspect extends ResourceCoordinatorAspect implements Ordered {

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }

    @Autowired
    public void setTransactionManager(TransactionManagerFactory transactionManagerFactory) {
        super.setTransactionManager(transactionManagerFactory.getTransactionManager());
    }
}

切面优先级为Ordered.HIGHEST_PRECEDENCE + 1,其在可补偿事务拦截器切面后执行。

(3)ResourceCoordinatorInterceptor资源协调拦截器

这个拦截器两个作用:
1 负责participant参与者对象的创建(条件:事务transaction对象不为null&&transaction.getStatus()事务状态为TRYING),然后将participant加入transaction的list中,并update入持久化存储;

2 并在try执行过程中,如果执行成功,设置ParticipantStatus.TRY_SUCCESS;如果失败,ParticipantStatus.TRY_FAILED。

总结:

ResourceCoordinatorInterceptor只在try阶段使用,负责participant的创建、添加入transaction、pjp.proceed执行try方法、根据try执行是否成功设置participant的执行状态。负责参与者的管理。

public class ResourceCoordinatorInterceptor {

    private TransactionManager transactionManager;

    public void setTransactionManager(TransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    public Object interceptTransactionContextMethod(TransactionMethodJoinPoint pjp) throws Throwable {

        Transaction transaction = transactionManager.getCurrentTransaction();

        if (transaction != null && transaction.getStatus().equals(TransactionStatus.TRYING)) { //1 

            //当事务状态为trying时,添加事务参与者
            Participant participant = enlistParticipant(pjp);

            Object result = null;
          //创建TransactionStatus.TRYING, ParticipantStatus.TRYING两个状态的事务上下文TransactionContext
            TransactionContext transactionContext = new TransactionContext(transaction.getRootDomain(), transaction.getRootXid(), participant.getXid(), TransactionStatus.TRYING, ParticipantStatus.TRYING);
            FactoryBuilder.factoryOf(participant.getTransactionContextEditorClass()).getInstance().set(transactionContext, pjp.getTarget(), pjp.getMethod(), pjp.getArgs());
            try {
                //执行try方法原逻辑
                result = pjp.proceed(pjp.getArgs());
              //如果执行成功,设置参与者participantStatus为TRY_SUCCESS
                participant.setStatus(ParticipantStatus.TRY_SUCCESS);
            } catch (Throwable e) {
                participant.setStatus(ParticipantStatus.TRY_FAILED);

                //if root transaction, here no need persistent transaction
                // because following stage is rollback, transaction's status is changed to CANCELING and save
//                    transactionManager.update(participant);
                throw e;
            } finally {
                FactoryBuilder.factoryOf(participant.getTransactionContextEditorClass()).getInstance().clear(transactionContext, pjp.getTarget(), pjp.getMethod(), pjp.getArgs());
            }


            return result;
        } //1 
      
      //如果不需要加入participant对象到transaction,那么执行方法原逻辑(即拦截器链,继续向下执行,try方法)
        return pjp.proceed(pjp.getArgs());
    }

  
    private Participant enlistParticipant(TransactionMethodJoinPoint pjp) {

        Transaction transaction = transactionManager.getCurrentTransaction();
        CompensableMethodContext compensableMethodContext = new CompensableMethodContext(pjp, transaction);

        String confirmMethodName = compensableMethodContext.getConfirmMethodName();
        String cancelMethodName = compensableMethodContext.getCancelMethodName();
        Class<? extends TransactionContextEditor> transactionContextEditorClass = compensableMethodContext.getTransactionContextEditorClass();
        TransactionXid xid = TransactionXid.withUniqueIdentity(null);

        Class targetClass = compensableMethodContext.getDeclaredClass();

        InvocationContext invocationContext = new InvocationContext(targetClass,
                confirmMethodName,
                cancelMethodName,
                compensableMethodContext.getMethod().getParameterTypes(), compensableMethodContext.getArgs());

      //构造参与者Participant
        Participant participant =
                new Participant(
                        transaction.getRootDomain(),
                        transaction.getRootXid(),
                        xid,
                        invocationContext,
                        transactionContextEditorClass);

      //将participant加入transactionManager的当前transaction的list<Participant>中,然后update
        transactionManager.enlistParticipant(participant);
        return participant;
    }
}
posted @ 2023-06-12 18:31  LeasonXue  阅读(58)  评论(0编辑  收藏  举报