LCN(5.0.2) lcn模式原始碼分析(二)
前言
上一篇文章( https://segmentfault.com/a/11... )我們在springboot2.1.3上集成了lcn5.0.2並簡單做了一個lcn模式的demo。LCN官網將原始碼都給了出來,但是分析原始碼的部分目前還不是很多,這篇文章主要分析一下LCN模式原始碼
事務控制原理
分析原始碼之前,我們首先看一下LCN整體的框架模型:
TX-LCN由兩大模組組成, TxClient、TxManager。TxClient作為模組的依賴框架,提供TX-LCN的標準支援,TxManager作為分散式事務的控制放。事務發起方或者參與反都由TxClient端來控制。
原理圖:
lcn模式
不難發現,開啟處理的地方在攔截器(com.codingapi.txlcn.tc.aspect.TransactionAspect)裡面
@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); } }