前言

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