分布式事务Seata框架底层源码分析

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。

  • TC:事务管理器
  • TM:事务开始服务
  • RM:事务参与过程的其他服务

底层实现流程

  • TM和RM都连接到我们的事务协调器TC。
  • TM和RM服务的数据源都被Seata代理,执行语句的前后会保存两条记录,一条是执行前的记录,一条是执行后的记录,是方便后期可以逆向的生成sql去回滚事务。具体记录存放在seata的undo_log表中。
  • TM在使用RPC-Feign远程调用的时候,在ThreadLocal中获取xid。
  • RM在请求头中取到该xid,设置到threadLocal中,同时向seata注册本地事务。
  • TM将当前本地事务的结果发送给TC,TC最后通知所有分支事务是提交或回滚。
  • TM如果调用接口成功之后再抛出异常时,告诉协调者TC,协调者TC再通知到所有分支的事务,根据undo_log逆向回滚事务。
  • 最后如果没有任何异常,TM通知TC,TC最后让所有的有该全局xid的undo_log中的记录都删除。
Seata和LCN的回滚之间有什么区别?

基本实现思路一样,唯一区别在于回滚方式,LCN采用代理数据源加关闭连接,暂时不支持提交本地事务,容易造成数据的死锁。
Seata采用undo_log的形式逆向生成sql,去实现回滚。

Seata生成全局ID源码部分

核心注解在于@GlobalTransactional
引入seata核心依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-seata</artifactId>
    <version>2.1.1.RELEASE</version>
</dependency>

先看到spring.factories配置文件
看到com.alibaba.cloud.seata.GlobalTransactionAutoConfiguration,
这个类
点进去,可以看到,这就是初始化seata的一个配置类。
并且注入全局事务扫描器,如下代码

	@Bean
	public GlobalTransactionScanner globalTransactionScanner() {
   
   

		String applicationName = applicationContext.getEnvironment()
				.getProperty("spring.application.name");

		String txServiceGroup = seataProperties.getTxServiceGroup();

		if (StringUtils.isEmpty(txServiceGroup)) {
   
   
			txServiceGroup = applicationName + "-seata-service-group";
			seataProperties.setTxServiceGroup(txServiceGroup);
		}

		return new GlobalTransactionScanner(applicationName, txServiceGroup);
	}

点到全局事务扫描类中
public class GlobalTransactionScanner extends AbstractAutoProxyCreator
implements InitializingBean, ApplicationContextAware,
DisposableBean
可以看到全局事务扫描类继承/实现了以下的接口,那么分别是做啥用的呢?
首先我们根据SpringBean和Aop的源码不难发现
AbstractAutoProxyCreator就是Aop原生的一个代理类
而InitializingBean属于Spring的Bean中的一个注解,执行动作在Bean实例化之后执行。
因此对于这个接口的回调方法中,就实现初始化的动作
源码如下

    @Override
    public void afterPropertiesSet() {
   
   
        if (disableGlobalTransaction) {
   
   
            if (LOGGER.isInfoEnabled()) {
   
   
                LOGGER.info("Global transaction is disabled.");
            }
            return;
        }
        initClient();

    }

    private void initClient() {
   
   
        if (LOGGER.isInfoEnabled()) {
   
   
            LOGGER.info("Initializing Global Transaction Clients ... ");
        }
        if (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
   
   
            throw new IllegalArgumentException(
                "applicationId: " + applicationId + ", txServiceGroup: " + txServiceGroup);
        }
        //init TM
        TMClient.init(applicationId, txServiceGroup);
        if (LOGGER.isInfoEnabled()) {
   
   
            LOGGER.info(
                "Transaction Manager Client is initialized. applicationId[" + applicationId + "] txServiceGroup["
                    + txServiceGroup + "]");
        }
        //init RM
        RMClient.init(applicationId, txServiceGroup);
        if (LOGGER.isInfoEnabled()) {
   
   
            LOGGER.info(
                "Resource Manager is initialized. applicationId[" + applicationId + "] txServiceGroup[" + txServiceGroup
                    + "]");
        }

        if (LOGGER.isInfoEnabled()) {
   
   
            LOGGER.info("Global Transaction Clients are initialized. ");
        }
        registerSpringShutdownHook();

    }

然后看到可以发现这两行代码

//init TM
TMClient.init(applicationId, txServiceGroup);
//init RM
RMClient.init(applicationId, txServiceGroup);

可以看到,在初始化方法中,就实现了初始化RM、TM然后,注册到TC中。
然后AbstractAutoProxyCreator这个抽象模板又是拿来干啥的呢?
对比下抽象类和这个实现类可以看到,主要是
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey)
重写了父类的这个回调方法。

看到实现类这个方法,
其作用就是,加上@GlobalTransactional这个注解后,当aop创建代理对象的时候,会走这个回调方法,去创建出GlobalTransactionalInterceptor对象。
点进去这个对象发现,哎,实现了MethodInterceptor接口,说明其采用CGLIB代理模式,进行代理,从而进行方法的反射。
Invoke()中就是其会执行的反射方法
具体源码如下

    @Override
    public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
   
   
        Class<?> targetClass = (methodInvocation.getThis() != null ? AopUtils.getTargetClass(methodInvocation.getThis()) : null);
        Method specificMethod = ClassUtils.getMostSpecificMethod(methodInvocation.getMethod(), targetClass);
        final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);

        final GlobalTransactional globalTransactionalAnnotation = getAnnotation(method, GlobalTransactional.class);
        final GlobalLock globalLockAnnotation = getAnnotation(method, GlobalLock.class);
        if (globalTransactionalAnnotation != null) {
   
   
            return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
        } else if (globalLockAnnotation != null) {
   
   
            return handleGlobalLock(methodInvocation);
        } else {
   
   
            return methodInvocation.proceed();
        }
    }

其中获取到两个注解

  • GlobalTransactional,判断你方法上有没有加上这个全局事务的注解
  • GlobalLock,作为分布式锁

因此直接点到handleGlobalTransaction()方法中
查看return transactionalTemplate.execute()这个execute方法
具体源码如下

    public Object execute(TransactionalExecutor business) throws Throwable {
   
   
        // 1. get or create a transaction
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

原味的你

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值