LCN(5.0.2) lcn模式源碼分析(二)

前言

上一篇文章(https://segmentfault.com/a/11...)咱們在springboot2.1.3上集成了lcn5.0.2並簡單作了一個lcn模式的demo。LCN官網將源碼都給了出來,可是分析源碼的部分目前還不是不少,這篇文章主要分析一下LCN模式源碼spring

事務控制原理

分析源碼以前,咱們首先看一下LCN總體的框架模型:
TX-LCN由兩大模塊組成, TxClient、TxManager。TxClient做爲模塊的依賴框架,提供TX-LCN的標準支持,TxManager做爲分佈式事務的控制放。事務發起方或者參與反都由TxClient端來控制。segmentfault

原理圖:
圖片描述api

lcn模式

不難發現,開啓處理的地方在攔截器(com.codingapi.txlcn.tc.aspect.TransactionAspect)裏面springboot

@Around("lcnTransactionPointcut() && !txcTransactionPointcut()" +
            "&& !tccTransactionPointcut() && !txTransactionPointcut()")
    public Object runWithLcnTransaction(ProceedingJoinPoint point) throws Throwable {
        //將執行分佈式事務的方法放在DTXInfo對象裏面
        DTXInfo dtxInfo = DTXInfo.getFromCache(point);
        LcnTransaction lcnTransaction = dtxInfo.getBusinessMethod().getAnnotation(LcnTransaction.class);
        dtxInfo.setTransactionType(Transactions.LCN);
        dtxInfo.setTransactionPropagation(lcnTransaction.propagation());
        
        //調用方法,正式開啓(或繼續,這裏取決因而否是事務發起方)分佈式事務
        return dtxLogicWeaver.runTransaction(dtxInfo, point::proceed);
    }

走進runTransaction方法,咱們能夠看到一下內容(僞代碼,方便分析)框架

public class DTXLogicWeaver {
    
    //執行分佈式事務的核心方法
    public Object runTransaction(){
    
        //1.拿到當前模塊的事務上下文和全局事務上下文
        DTXLocalContext dtxLocalContext = DTXLocalContext.getOrNew();
        TxContext txContext;
        // ---------- 保證每一個模塊在一個DTX下只會有一個TxContext ---------- 
        if (globalContext.hasTxContext()) {
            // 有事務上下文的獲取父上下文
            txContext = globalContext.txContext();
            dtxLocalContext.setInGroup(true);//加入事務組
            log.debug("Unit[{}] used parent's TxContext[{}].", dtxInfo.getUnitId(), txContext.getGroupId());
        } else {
            // 沒有的開啓本地事務上下文
            txContext = globalContext.startTx();//下層建立了事務組
        }
        
        //2.設置本地事務上下文的一些參數
        if (Objects.nonNull(dtxLocalContext.getGroupId())) {
            dtxLocalContext.setDestroy(false);
        }
        dtxLocalContext.setUnitId(dtxInfo.getUnitId());
        dtxLocalContext.setGroupId(txContext.getGroupId());//從全局上下文獲取
        dtxLocalContext.setTransactionType(dtxInfo.getTransactionType());
        
       
        //3.設置分佈式事務參數
        TxTransactionInfo info = new TxTransactionInfo();
        info.setBusinessCallback(business);//業務執行器(核心)
        info.setGroupId(txContext.getGroupId());//從全局上下文獲取
        info.setUnitId(dtxInfo.getUnitId());
        info.setPointMethod(dtxInfo.getBusinessMethod());
        info.setPropagation(dtxInfo.getTransactionPropagation());
        info.setTransactionInfo(dtxInfo.getTransactionInfo());
        info.setTransactionType(dtxInfo.getTransactionType());
        info.setTransactionStart(txContext.isDtxStart());
        
        
        
        //4.LCN事務處理器
        try {
            return transactionServiceExecutor.transactionRunning(info);
        } finally {
            // 線程執行業務完畢清理本地數據
            if (dtxLocalContext.isDestroy()) {
                // 通知事務執行完畢 
                synchronized (txContext.getLock()) {
                    txContext.getLock().notifyAll();
                }

                // TxContext生命週期是? 和事務組同樣(不與具體模塊相關的)
                if (!dtxLocalContext.isInGroup()) {
                    globalContext.destroyTx();
                }

                DTXLocalContext.makeNeverAppeared();
                TracingContext.tracing().destroy();
            }
            log.debug("<---- TxLcn end ---->");
        }      
    } 
}

執行業務操做分佈式

/**
     * 事務業務執行
     *
     * @param info info
     * @return Object
     * @throws Throwable Throwable
     */
    public Object transactionRunning(TxTransactionInfo info) throws Throwable {

        // 1. 獲取事務類型
        String transactionType = info.getTransactionType();

        // 2. 獲取事務傳播狀態
        DTXPropagationState propagationState = propagationResolver.resolvePropagationState(info);

        // 2.1 若是不參與分佈式事務當即終止
        if (propagationState.isIgnored()) {
            return info.getBusinessCallback().call();
        }

        // 3. 獲取本地分佈式事務控制器
        DTXLocalControl dtxLocalControl = txLcnBeanHelper.loadDTXLocalControl(transactionType, propagationState);

        // 4. 織入事務操做
        try {
            // 4.1 記錄事務類型到事務上下文
            Set<String> transactionTypeSet = globalContext.txContext(info.getGroupId()).getTransactionTypes();
            transactionTypeSet.add(transactionType);

            dtxLocalControl.preBusinessCode(info);

            // 4.2 業務執行前
            txLogger.txTrace(
                    info.getGroupId(), info.getUnitId(), "pre business code, unit type: {}", transactionType);

            // 4.3 執行業務
            Object result = dtxLocalControl.doBusinessCode(info);

            // 4.4 業務執行成功
            txLogger.txTrace(info.getGroupId(), info.getUnitId(), "business success");
            dtxLocalControl.onBusinessCodeSuccess(info, result);
            return result;
        } catch (TransactionException e) {
            txLogger.error(info.getGroupId(), info.getUnitId(), "before business code error");
            throw e;
        } catch (Throwable e) {
            // 4.5 業務執行失敗
            txLogger.error(info.getGroupId(), info.getUnitId(), Transactions.TAG_TRANSACTION,
                    "business code error");
            dtxLocalControl.onBusinessCodeError(info, e);
            throw e;
        } finally {
            // 4.6 業務執行完畢
            dtxLocalControl.postBusinessCode(info);
        }
    }
相關文章
相關標籤/搜索