
一、概述
Seata 依赖 Spring 的注解机制,实现声明式事务,即开发者给 Bean 使用@GlobalTransactional注解 ,Seata 通过GlobalTransactionScanner重写此类 Bean 生命周期的三个阶段以完成分布式事务能力,这 3 步为:
-
Bean 初始化阶段(`afterPropertiesSet()``)
- 初始化 TM RM 客户端,建立与 TC 的长连接
-
Bean 初始化后阶段(`wrapIfNecessary()``)
wrapIfNecessary见名知意,如果有必要就包裹(wrap)起来;所以如果 Bean 的方法上有注解@GlobalTransactional(@GlobalLock,@TwoPhaseBusinessAction注解本篇暂不提及),则给这类 Bean 生成代理类,目标方法的代理逻辑中实现分布式事务中 TM 角色的能力
-
Bean 销毁阶段(ShutdownHook)
- 当 Bean 被销毁的时候关闭 TM、RM 客户端
本篇 RM、RM 客户端的初始化,暂不多说,后续会结合注册中心和重连机制再提,其中跟 Netty 相关的部分逻辑在《Seata 高性能 RPC 通信的实现- 巧用 reactor 模式》中有提及
二、@GlobalTransactional核心逻辑串烧
1)GlobalTransactionScanner#wrapIfNecessary扫描 spring bean 时,判断是否有@GlobalTransactional注解(@GlobalLock,此处不提),识别到方法上的@GlobalTransactional注解后,给 bean 加上 AOP 拦截器GlobalTransactionalInterceptor。TCC 模式下方法被@TwoPhaseBusinessAction修饰时,相应的Advice为TccActionInterceptor
2)当目标方法被调用时,就先进入到了GlobalTransactionalInterceptor#invoke中,此方法中首先判断是否在运行时停用分布式事务能力(1.动态配置关闭事务,2.因 Seata 异常降级事务能力);如果仍是启用状态,则后续逻辑交给handleGlobalTransaction来完成。
3)handleGlobalTransaction 中的关键逻辑是 2 步,第 1 步是通过GlobalTransactionalInterceptor#transactionalTemplate执行全局事务;第二步是对第一步结果异常时的处理,在第二部会有failureHandler的调用,开发者据此回调得知事务是错在哪里了。
4)在GlobalTransactionalInterceptor#transactionalTemplate中定义的是 TM 发起者执行开启全局事务、提交或回滚全局事务的核心逻辑,这些方法执行时会判断若角色是 TM 参与者则不做什么,有可能一个执行链路中有多个方法被@GlobalTransaction修饰,调用链路中第一个@GlobalTransaction才是 TM 发起者,剩余的都是 TM 参与者,此方法中的的关键逻辑如下:
- 从上下文中获取获取当前全局事务对象
GlobalTransaction(有可能一个执行链路中有多个方法被@GlobalTransaction 修饰) - 根据
@GlobalTransactional注解中propagation的值和当前全局事务对象的情况,决策事务传播策略,参考 Spring 文档了解事务传播行为 - 如果当前全局事务对象是空,则新建一个全局事务对象,角色是 TM 发起者
- 完成全局事务:开始全局事务,执行业务逻辑(AT 模式下,各分支事务的执行就在其中),提交或者回滚全局事务。
三、@GlobalTransactional核心源码解读
1) GlobalTransactionScanner#wrapIfNecessary扫描 spring bean 时,判断方法上是否有@GlobalTransactional注解,如果有则给这个 bean,添加拦截器GlobalTransactionalInterceptor,也就是说被 @GlobalTransactional 和 @GlobalLock 标注后,Seata 通过 AOP 增强提供的分布式事务能力在 GlobalTransactionalInterceptor 中
scss
复制代码
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) { // ... TCC 部分暂略 Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean); Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean); // 判断类或方法上是否有@GlobalTransactional 注解 // 判断方法上有否有 @GlobalLock 注解 if (!existsAnnotation(new Class[]{serviceInterface}) && !existsAnnotation(interfacesIfJdk)) { return bean; } if (globalTransactionalInterceptor == null) { // 构建AOP的拦截器 GlobalTransactionalInterceptor globalTransactionalInterceptor = new GlobalTransactionalInterceptor(failureHandlerHook); // 运行时监听是否禁用分布式事务,如果禁用,那么拦截器中就不再使用分布式事务的能力 ConfigurationCache.addConfigListener( ConfigurationKeys.DISABLE_GLOBAL_TRANSACTION, (ConfigurationChangeListener)globalTransactionalInterceptor); } // 下方getAdvicesAndAdvisorsForBean 方法中,就返回这个interceptor, // 也就是说被 @GlobalTransactional 和 @GlobalLock 标注后,Seata通过AOP增强提供的分布式事务能力在 GlobalTransactionalInterceptor中 interceptor = globalTransactionalInterceptor; } LOGGER.info("Bean[{}] with name [{}] would use interceptor [{}]", bean.getClass().getName(), beanName, interceptor.getClass().getName()); // 如果是普通的bean,走父类的方法生成代理类即可 if (!AopUtils.isAopProxy(bean)) { bean = super.wrapIfNecessary(bean, beanName, cacheKey); } else { // 如果已经是代理类,获取到advisor后,添加到该集合即可 AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean); // 根据上面的interceptor生成advisor Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null)); int pos; for (Advisor avr : advisor) { // Find the position based on the advisor's order, and add to advisors by pos pos = findAddSeataAdvisorPosition(advised, avr); advised.addAdvisor(pos, avr); } } PROXYED_SET.add(beanName); return bean; } } catch (Exception exx) { throw new RuntimeException(exx); }
2) 拦截器GlobalTransact

Seata通过Spring的注解机制实现声明式事务管理,当Bean被扫描到有@GlobalTransactional注解时,Seata会生成代理类并添加AOP拦截器。拦截器在方法调用时处理全局事务,包括开启、提交或回滚。在事务执行过程中,根据@GlobalTransactional的propagation属性决定事务传播策略,并在异常时调用failureHandler进行相应处理。此外,Seata还提供了运行时开关,动态控制事务能力的启用或禁用,以及降级检查机制,当事务连续失败达到阈值时,会自动禁用事务能力。
最低0.47元/天 解锁文章
3852

被折叠的 条评论
为什么被折叠?



