tcc分散トランザクションソース解析シリーズ(五)のプロジェクト実戦

14262 ワード

前回、私たちはすでに消費全体の呼び出しの流れを分析して、今ただ本当のrpcの遠位呼び出しを開始するだけで、この文章、私たちは一緒に提供者の呼び出しの流れに入りましょう!
  • accountServicesを開始します.payment(accountDTO); の呼び出しは、プロバイダでAccountServiceImpl:
  • として表示されます.
    
    /**
        *     
        *
        * @param accountDTO   dto
        * @return true
        */
       @Override
       @Tcc(confirmMethod = "confirm", cancelMethod = "cancel")
       public boolean payment(AccountDTO accountDTO) {
           final AccountDO accountDO = accountMapper.findByUserId(accountDTO.getUserId());
           accountDO.setBalance(accountDO.getBalance().subtract(accountDTO.getAmount()));
           accountDO.setFreezeAmount(accountDO.getFreezeAmount().add(accountDTO.getAmount()));
           accountDO.setUpdateTime(new Date());
           final int update = accountMapper.update(accountDO);
           if (update != 1) {
               throw new TccRuntimeException("    !");
           }
           return Boolean.TRUE;
       }
    
       public boolean confirm(AccountDTO accountDTO) {
    
           LOGGER.debug("============        ===============");
    
           final AccountDO accountDO = accountMapper.findByUserId(accountDTO.getUserId());
           accountDO.setFreezeAmount(accountDO.getFreezeAmount().subtract(accountDTO.getAmount()));
           accountDO.setUpdateTime(new Date());
           accountMapper.update(accountDO);
           return Boolean.TRUE;
       }
    
    
       public boolean cancel(AccountDTO accountDTO) {
    
           LOGGER.debug("============        ===============");
           final AccountDO accountDO = accountMapper.findByUserId(accountDTO.getUserId());
           accountDO.setBalance(accountDO.getBalance().add(accountDTO.getAmount()));
           accountDO.setFreezeAmount(accountDO.getFreezeAmount().subtract(accountDTO.getAmount()));
           accountDO.setUpdateTime(new Date());
           accountMapper.update(accountDO);
           return Boolean.TRUE;
       }
    
    
  • @Tcc注釈もあり,confrim,cancelなどの真の方法を提供していることが分かった.前の分析を通じて、彼はspringBeanの実装クラスであり、同じように面を切ることを知っています.
  • TccTransactionFactoryServiceImplのfactoryOfメソッドを経て、P r o v i derTccTransactionHandler
  • に戻ることがわかります.
    @Override
       public Class factoryOf(TccTransactionContext context) throws Throwable {
    
           //           tcc       ,           
           if (!tccTransactionManager.isBegin() && Objects.isNull(context)) {
               return StartTccTransactionHandler.class;
           } else if (tccTransactionManager.isBegin() && Objects.isNull(context)) {
               return ConsumeTccTransactionIHandler.class;
           } else if (Objects.nonNull(context)) {
               return ProviderTccTransactionHandler.class;
           }
           return ConsumeTccTransactionIHandler.class;
       }
    
  • 最終的に私たちはP r o v i derTccTransactionHandlerに来ました.handlerメソッド:
  • /**
        *             
        *   tcc                 
        *
        * @param point   point   
        * @param context context
        * @return Object
        * @throws Throwable   
        */
       @Override
       public Object handler(ProceedingJoinPoint point, TccTransactionContext context) throws Throwable {
           TccTransaction tccTransaction = null;
           try {
               switch (TccActionEnum.acquireByCode(context.getAction())) {
                   case TRYING:
                       try {
                           //      
                           tccTransaction = tccTransactionManager.providerBegin(context);
                           //      
                           return point.proceed();
                       } catch (Throwable throwable) {
                           tccTransactionManager.removeTccTransaction(tccTransaction);
                           throw throwable;
    
                       }
                   case CONFIRMING:
                       //   confirm                   
                       final TccTransaction acquire = tccTransactionManager.acquire(context);
                       tccTransactionManager.confirm();
                       break;
                   case CANCELING:
                       //     CANCELING                   
                       tccTransactionManager.acquire(context);
                       tccTransactionManager.cancel();
                       break;
                   default:
                       break;
               }
           } finally {
               tccTransactionManager.remove();
           }
           Method method = ((MethodSignature) (point.getSignature())).getMethod();
           return getDefaultValue(method.getReturnType());
       }
    
    
  • TccTransactionContextはrpc jsonシーケンス化によって伝達されたオブジェクトであり、このときtryフェーズであることが分かったのでtry
  • に入ります.
    try {
        //      
        tccTransaction = tccTransactionManager.providerBegin(context);
        //      
        return point.proceed();
    } catch (Throwable throwable) {
        tccTransactionManager.removeTccTransaction(tccTransaction);
        throw throwable;
    
    }
    
  • まず、プロバイダのトランザクション情報を作成し、彼を保存し、threadlocalに保存し、pointを開始します.Proceed()が呼び出されると、tryフェーズで最終的に
  • に入るため、TccCoordinatorMethodAspectに入ります.
    /**
        *               
        *
        * @param point   
        */
       private void registerParticipant(ProceedingJoinPoint point, String transId) throws NoSuchMethodException {
    
           MethodSignature signature = (MethodSignature) point.getSignature();
           Method method = signature.getMethod();
    
           Class> clazz = point.getTarget().getClass();
    
           Object[] args = point.getArgs();
    
           final Tcc tcc = method.getAnnotation(Tcc.class);
    
           //      
           String confirmMethodName = tcc.confirmMethod();
    
          /* if (StringUtils.isBlank(confirmMethodName)) {
               confirmMethodName = method.getName();
           }*/
    
           String cancelMethodName = tcc.cancelMethod();
    
          /* if (StringUtils.isBlank(cancelMethodName)) {
               cancelMethodName = method.getName();
           }
    */
           //    
           final TccPatternEnum pattern = tcc.pattern();
    
           tccTransactionManager.getCurrentTransaction().setPattern(pattern.getCode());
    
    
           TccInvocation confirmInvocation = null;
           if (StringUtils.isNoneBlank(confirmMethodName)) {
               confirmInvocation = new TccInvocation(clazz,
                       confirmMethodName, method.getParameterTypes(), args);
           }
    
           TccInvocation cancelInvocation = null;
           if (StringUtils.isNoneBlank(cancelMethodName)) {
               cancelInvocation = new TccInvocation(clazz,
                       cancelMethodName,
                       method.getParameterTypes(), args);
           }
    
    
           //     
           final Participant participant = new Participant(
                   transId,
                   confirmInvocation,
                   cancelInvocation);
    
           tccTransactionManager.enlistParticipant(participant);
    
       }
    
    
  • ここでは、実際のconfrim、cancelメソッドを取得し、現在のトランザクション情報に格納します.その後、実際のビジネスコール、すなわちpaymentメソッドを実行する:
  • 
      @Override
      @Tcc(confirmMethod = "confirm", cancelMethod = "cancel")
      public boolean payment(AccountDTO accountDTO) {
          final AccountDO accountDO = accountMapper.findByUserId(accountDTO.getUserId());
          accountDO.setBalance(accountDO.getBalance().subtract(accountDTO.getAmount()));
          accountDO.setFreezeAmount(accountDO.getFreezeAmount().add(accountDTO.getAmount()));
          accountDO.setUpdateTime(new Date());
          final int update = accountMapper.update(accountDO);
          if (update != 1) {
              throw new TccRuntimeException("    !");
          }
          return Boolean.TRUE;
      }
    
    
  • メソッドを実行すると、戻ってきます.私がどこでこのメソッドを実行したか覚えていますか.はい、もちろんうどんです.私たちはうどんの中で実行しています.私たちはPaymentServiceImplです.makePaymentうどんの中で実行されます!この点を理解してください.実行後、inventoryServicesを開始しました.decrease(inventoryDTO)は彼の呼び出し原理を上と同じように呼び出し、異なるモジュールで実行するだけだ.makePaymentメソッドの実行が完了したら、どのように実行しますか?StartTccTransactionHandlerを覚えていますか.ずっとそこで待っていますよ.彼のコードを振り返ってみましょう:
  • @Override
       public Object handler(ProceedingJoinPoint point, TccTransactionContext context) throws Throwable {
           Object returnValue;
           try {
               tccTransactionManager.begin();
               try {
                   //       try  
                   returnValue = point.proceed();
    
               } catch (Throwable throwable) {
                   //    cancel
    
                   tccTransactionManager.cancel();
    
                   throw throwable;
               }
               //try    confirm confirm     ,         
               tccTransactionManager.confirm();
           } finally {
               tccTransactionManager.remove();
           }
           return returnValue;
       }
    
  • 結局、私たちはこんなに長い間歩いていましたが、実はここまで来て、私たちはreturnValue=pointを実行しました.proceed(); このコード.

  • 異常なし
  • tcTransactionManagerを実行します.confirm(); コードを見てみましょう
  • /**
         *   confirm                              ,          confirm
         *            confirm  。。
         */
        void confirm() throws TccRuntimeException {
    
            LogUtil.debug(LOGGER, () -> "    tcc confirm   !start");
    
            final TccTransaction currentTransaction = getCurrentTransaction();
    
            if (Objects.isNull(currentTransaction)) {
                return;
            }
    
            currentTransaction.setStatus(TccActionEnum.CONFIRMING.getCode());
    
            coordinatorCommand.execute(new CoordinatorAction(CoordinatorActionEnum.UPDATE, currentTransaction));
    
            final List participants = currentTransaction.getParticipants();
            List participantList = Lists.newArrayListWithCapacity(participants.size());
            boolean success = true;
            Participant fail = null;
            if (CollectionUtils.isNotEmpty(participants)) {
                for (Participant participant : participants) {
                    try {
                        TccTransactionContext context = new TccTransactionContext();
                        context.setAction(TccActionEnum.CONFIRMING.getCode());
                        context.setTransId(participant.getTransId());
                        TransactionContextLocal.getInstance().set(context);
                        //      rpc confrim  
                        executeParticipantMethod(participant.getConfirmTccInvocation());
                        participantList.add(participant);
                    } catch (Exception e) {
                        LogUtil.error(LOGGER, "  confirm    :{}", () -> e);
                        success = false;
                        fail = participant;
                        break;
                    }
                }
            }
            executeHandler(success, currentTransaction, fail, participantList, participants);
        }
        private void executeHandler(boolean success, final TccTransaction currentTransaction, Participant fail,
                                    List participantList, final List participants) {
            if (success) {
                TransactionContextLocal.getInstance().remove();
                coordinatorCommand.execute(new CoordinatorAction(CoordinatorActionEnum.DELETE, currentTransaction));
            } else {
                //       ,       
                final List updateList =
                        participants.stream().skip(participantList.size()).collect(Collectors.toList());
                currentTransaction.setParticipants(updateList);
                coordinatorCommand.execute(new CoordinatorAction(CoordinatorActionEnum.UPDATE, currentTransaction));
                assert fail != null;
                throw new TccRuntimeException(fail.getConfirmTccInvocation().toString());
            }
        }
    
        private void executeParticipantMethod(TccInvocation tccInvocation) throws Exception {
           if (Objects.nonNull(tccInvocation)) {
               final Class clazz = tccInvocation.getTargetClass();
               final String method = tccInvocation.getMethodName();
               final Object[] args = tccInvocation.getArgs();
               final Class[] parameterTypes = tccInvocation.getParameterTypes();
               final Object bean = SpringBeanUtils.getInstance().getBean(clazz);
               MethodUtils.invokeMethod(bean, method, args, parameterTypes);
    
           }
       }
    
    
  • このコードの論理は、簡単に理解すると、まず現在のトランザクションステータス(confrim)を更新し、現在のトランザクションの呼び出しポイントのconfrimメソッドを取得し、コンテキストを設定し、反射呼び出しを開始します.
  • 実はここではデバッグによってconfrimを開始する方法がAccountServicesであることがわかりました.payment(AccountDTO accountDTO)ですが、設定されたコンテキスト状態はconfrimで、反射呼び出しを開始するとP r o v i derTcccTransactionHandlerに着きます.handlerメソッド、このメソッドはまだ印象に残っているかもしれませんが、コードを見てみましょう.
  • @Override
        public Object handler(ProceedingJoinPoint point, TccTransactionContext context) throws Throwable {
            TccTransaction tccTransaction = null;
            try {
                switch (TccActionEnum.acquireByCode(context.getAction())) {
                    case TRYING:
                        try {
                            //      
                            tccTransaction = tccTransactionManager.providerBegin(context);
                            //      
                            return point.proceed();
                        } catch (Throwable throwable) {
                            tccTransactionManager.removeTccTransaction(tccTransaction);
                            throw throwable;
    
                        }
                    case CONFIRMING:
                        //   confirm                   
                        final TccTransaction acquire = tccTransactionManager.acquire(context);
                        tccTransactionManager.confirm();
                        break;
                    case CANCELING:
                        //     CANCELING                   
                        tccTransactionManager.acquire(context);
                        tccTransactionManager.cancel();
                        break;
                    default:
                        break;
                }
            } finally {
                tccTransactionManager.remove();
            }
            Method method = ((MethodSignature) (point.getSignature())).getMethod();
            return getDefaultValue(method.getReturnType());
        }
    
    
  • ここではコンテキスト設定の状態がCONFIRMINGであるため、
  • が実行されます.
    //   confirm                   
    final TccTransaction acquire = tccTransactionManager.acquire(context);
    tccTransactionManager.confirm();
    break;
    
  • tcTransactionManagerを追跡します.confirm(); 以前と同じ方法であることがわかります.この方法はaccountマイクロサービスで
  • を実行していることを知っておく必要があります.
  • ですので、AccountServiceImplが最後に実行されます.confirmメソッドで、支払い確認を行いました.

  • 同理cancel法も上述したような原理で実行される.
    ここまで、私达は解析し终わって、全体のtcc过程の実行の流れ、みんなの肝心な点はAOPを理解して、切面の思想を理解して、実はとても简単な事で、もし何か疑问と问题があれば、QQ群に参加することを歓迎します:162614487