内容简介:上一篇文章(
前言
上一篇文章( 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); } }
以上所述就是小编给大家介绍的《LCN(5.0.2) lcn模式源码分析(二)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 从源码角度理解Java设计模式——装饰者模式 原 荐
- 设计模式之发布订阅模式(5) Spring Events源码解析
- EventBus源码剖析(3) — 线程模式
- Mybatis源码解读-设计模式总结
- 深入理解《单例模式》之源码分析
- Seata AT 模式启动源码分析
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
电子邮件营销密码
[美] Jeanniey Mullen、David Daniesl / 薛剑韬 / 人民邮电出版社 / 2009-9 / 39.00元
在当今互联网蓬勃发展的形势下,电子邮件是互联网应用最广的服务之一。那么如何利用其作为有效的营销工具呢?本书系统地讲解了美国电子邮件营销的预算统筹、营销策略、管理模式、执行机制、涉及的技术、营销实施的细节等,其方法有很强的可循性,并可预见将获得的成果。阅读本书之后,读者会深刻感受到电子邮件营销的博大精深,它既是一门扎实严谨的科学,又是一项充满创造力的艺术。. 本书适合企业管理人员及市场营销人员......一起来看看 《电子邮件营销密码》 这本书的介绍吧!