4000-520-616
欢迎来到免疫在线!(蚂蚁淘生物旗下平台)  请登录 |  免费注册 |  询价篮
主营:原厂直采,平行进口,授权代理(蚂蚁淘为您服务)
咨询热线电话
4000-520-616
当前位置: 首页 > 新闻动态 >
新闻详情
【SEATA源码分析】 tm 模块源码解析_赵润泽-CSDN博客
来自 : CSDN技术社区 发布时间:2021-03-24

一 .导读

首先放一张tm模块的主要类关系图
\"在这里插入图片描述\"
从图中可以很明显的看出 模块暴露出去的类是 TransactionalTemplate 模板类中找 GlobalTransactionalContext 类获取业务业务类 而业务类持有了一个 TrancationManagerHolder 类 即由 TransactionManager 的实现类封装成的单例持有类 holder 通过SPI的方式加载配置文件中配置的具体的 TransactionManager 的实现类 0.9的版本默认实现类是 DefaultTransactionManager 这个类即模板方法处理业务的类。

上面这五个类 真正有用的就是两个类 一个template和一个defaultTransactionManager 一个模板方法类 一个具体的业务实现类 而tm封装这么多 是为了增加扩展点 为将来的扩展留下空间。

比如你可以修改SPI配置文件中 TransactionManager 的实现类 来扩展模板方法的实现。甚至你还可以替换 GlobalTrancationalInterceptor(Spring模块) 中持有的 TrancactionalTemplate 彻底告别tm模块 自己实现具体的业务。

二 . model类分析

首先是 template 模板参数需要的类 TransactionalExecutor 这是一个接口类
\"在这里插入图片描述\"
execute()是用来执行业务逻辑的类 而 getTransactionInfo() 用来获取 GlobalTransactional 注解的信息。
GlobalTransactionalInterceptor 在调用模板类的 execute(transactionalExecutor)方法的时候 注入了业务执行逻辑的类和从注解上获取到的信息 即实现了上面的接口类 是匿名类的形式。

TransactionalExecutor 接口类中还有一个子类 即 Exception 的子类 ExecutionException 是对执行时异常的封装。

还有一个enum类 对失败步骤记录状态的集合的封装。

接下来是 TransactionInfo 类 类中的属性用来记录 GlobalTransactional 的信息 注解中的 rollbackFor 和 noRollbackFor 的异常类 根据一场的类名 封装成了 RoolbackRule 和 NoRollbackRule NoRollbackRule 是 RollbackRule 的子类 info类中有一个判断参数中异常类是否要回滚的遍历的方法很有意思
\"在这里插入图片描述\"
这个方法中有一个很重要的 deepest 刚开始我还以为这个变量没什么用 因为只要返回 boolean 不需要知道到底是 roolbackRules 中的哪一个起作用了 还在github上提了一个 pr 结果被大佬教育了。。。

其实这里 deepest 是用来确定 winner 的是子类 父类的 depth 会高一点。而 roolbackRules中放置的是回滚和不回滚的类的集合。

roolbackRules这个集合是 LinkHashSet 即如果有相同的异常(因为RollbackRule重写了 hashcode(exceptionName) 所以这里的相同是指 exceptioName 相同 后面的类会覆盖前面的 在 template 类中 解析注解 GlobalTransactional 顺序是先解析回滚的 再解析不回滚的 所以这里如果回滚的和不回滚的有相同的异常 最终效果是不回滚。

三 .模板类分析

模板类的 execute(TransactionalExecutor) 方法很清晰 下面一步一步的来分析
\"在这里插入图片描述\"
1.获取当前的全局事务(能获取到xid)或者创建一个全局事务(xid暂时为空) 全局事务有一个属性 enum 类型 有两个角色 一个是 Launcher 一个是 Participant 即发起者或者参与者。

2.开始全局事务 这里最终会调用 DefaultTransactionManager 即 TM 去向 TC 注册全局事务 获取注册的状态 如果成功会有 xid 并绑定到上下文中。参与者全局事务在注册之前就可以获取到xid。

3.执行业务就不说了 直接看如果执行业务出现异常 这里需要根据 TransactionInfo( GlobalTransaction) 的 roolbackOn(ex) 判断是否是需要回滚的异常 如果不是 执行4提交事务。如果是 则调用DTM进行异常的回滚 并且获取本次回滚后的状态 绑定到属性中 并抛出异常。

4.上报事务的提交结果。角色是参与者的事务是没有职责上报状态的。

5.移除所有的Hook类 即钩子类。

上述模板流程 如果是成功的 则返回执行结果 如果是失败的 则抛出导致失败的异常 交给上层处理。

上层调用类 GlobalTransactionInterceptor 也没有对业务产生的异常进行处理 直接抛给了上层。这里的上层即是 srping 管理的范围 spring 会对异常进行处理。

在 template 方法中 如果因为 seata 框架对事务流程的处理而抛出的异常 则由模板类封装对应的异常 上述5个步骤 每一个步骤都有对应的异常 模板方法把异常抛给 GlobalTransactionInterceptor 在这个类中 先是调用 DefaultFailureHandlerImpl 处理 然后再抛给上层 即 spring 处理。

四 .流程的异常处理

现在的版本0.9 有一个 failureHandler 的默认处理类 DefaultFailureHandler 这个类维持了一个 HashedWheelTimer(netty包中) 周期性执行任务的线程池类 目前池中只实例化了一个线程。这个类和 newSchedulerThreadPool 生成的线程池类似 都是周期性的执行任务 seata没有自己写周期性执行任务的线程池 而是复用了netty的。

这个线程池的任务是输出当前事务的状态 即 DefaultGlobalTransaction 中 status 的状态
\"在这里插入图片描述\"
这里对事务状态的判断比较难理解 这里用提交失败处理来分析
当发生 onCommitFailure 给线程池增加一个任务

timer.newTimeout(new CheckTimerTask(tx, GlobalStatus.Committed), SCHEDULE_INTERVAL_SECONDS, TimeUnit.SECONDS);

shouldShop()中会判断 interceptor 传递过来的 tx 中 status 的状态 是否是 GlobalStatus.commited 即是否是提交完成的状态。

这里肯定不会是提交完成的状态 因为提交完成不会抛出异常 就不会进入 failureHandler 的处理方法中。所以 tx 中的 status 的状态和 required 不一样 返回false 这个 run() 方法结束。

这里另起一个线程 主要是为了进行状态的校验 确定一下失败操作是否是正确的 并且输出日志

LOGGER.info( transaction[ tx.getXid() ] current status is [ status ] );

结合上面 onCommitFailureHandler() 中的日志

LOGGER.warn( Failed to commit transaction[ tx.getXid() ] , cause);

一个警告级别 输出未能提交事务的异常原因 一个info级别 输出当前事务的状态。便于定位处理异常。

五 .总结

至此 tm 模块就分析完了 这个模块代理被 GlobalTransaction 注解的方法 纳入自己的事务处理中。
对外表现是
1.提供了 template 模板处理流程的方法 供 spring 模块的 interceptor 调用。
2.代理了业务类 等于包裹了业务类 业务类的前置后置都有处理逻辑。
3.发生业务异常时 事务流程处理完毕 还会把异常抛给上层 即 spring 处理。

更多好文请关注微信公众号 我手一杯
\"在这里插入图片描述\"

本文链接: http://tranglobe.immuno-online.com/view-682001.html

发布于 : 2021-03-24 阅读(0)
公司介绍
联络我们
服务热线:4000-520-616
(限工作日9:00-18:00)
QQ :1570468124
手机:18915418616
官网:http://