前言
上一篇文章(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); } }