1、Seata之TM源码分析

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。
Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

1、SeataAutoConfiguration

在该核心类中主要创建事务管理器之 GlobalTransactionScanner 实例 & 资源管理器 SeataAutoDataSourceProxyCreator

@ComponentScan(basePackages = "io.seata.spring.boot.autoconfigure.properties")
@ConditionalOnProperty(prefix = StarterConstants.SEATA_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
@Configuration
@EnableConfigurationProperties({
    
    SeataProperties.class})
public class SeataAutoConfiguration {
    
    
    private static final Logger LOGGER = LoggerFactory.getLogger(SeataAutoConfiguration.class);

    @Bean(BEAN_NAME_SPRING_APPLICATION_CONTEXT_PROVIDER)
    @ConditionalOnMissingBean(name = {
    
    BEAN_NAME_SPRING_APPLICATION_CONTEXT_PROVIDER})
    public SpringApplicationContextProvider springApplicationContextProvider() {
    
    
        return new SpringApplicationContextProvider();
    }

    @Bean(BEAN_NAME_FAILURE_HANDLER)
    @ConditionalOnMissingBean(FailureHandler.class)
    public FailureHandler failureHandler() {
    
    
        return new DefaultFailureHandlerImpl();
    }

    @Bean
    @DependsOn({
    
    BEAN_NAME_SPRING_APPLICATION_CONTEXT_PROVIDER, BEAN_NAME_FAILURE_HANDLER})
    @ConditionalOnMissingBean(GlobalTransactionScanner.class)
    public GlobalTransactionScanner globalTransactionScanner(SeataProperties seataProperties, FailureHandler failureHandler) {
    
    
        if (LOGGER.isInfoEnabled()) {
    
    
            LOGGER.info("Automatically configure Seata");
        }
        return new GlobalTransactionScanner(seataProperties.getApplicationId(), seataProperties.getTxServiceGroup(), failureHandler);
    }

    @Bean(BEAN_NAME_SEATA_AUTO_DATA_SOURCE_PROXY_CREATOR)
    @ConditionalOnProperty(prefix = StarterConstants.SEATA_PREFIX, name = {
    
    "enableAutoDataSourceProxy", "enable-auto-data-source-proxy"}, havingValue = "true", matchIfMissing = true)
    @ConditionalOnMissingBean(SeataAutoDataSourceProxyCreator.class)
    public SeataAutoDataSourceProxyCreator seataAutoDataSourceProxyCreator(SeataProperties seataProperties) {
    
    
        return new SeataAutoDataSourceProxyCreator(seataProperties.isUseJdkProxy(),seataProperties.getExcludesForAutoProxying());
    }
}

2、GlobalTransactionScanner

GlobalTransactionScanner实现了BeanPostProcessor子类之AbstractAutoProxyCreator。核心方法wrapIfNecessary在BeanPostProcessor之postProcessAfterInitialization方法调用中完成回调。

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
    
    
    if (disableGlobalTransaction) {
    
    
        return bean;
    }
    try {
    
    
        synchronized (PROXYED_SET) {
    
    
            if (PROXYED_SET.contains(beanName)) {
    
    
                return bean;
            }
            interceptor = null;
            //check TCC proxy
            if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
    
    
                //TCC interceptor, proxy bean of sofa:reference/dubbo:reference, and LocalTCC
                interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
            } else {
    
    
                Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);
                Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);
                if (!existsAnnotation(new Class[]{
    
    serviceInterface})
                    && !existsAnnotation(interfacesIfJdk)) {
    
    // 判断是否存在GlobalTransactional、GlobalLock注解
                    return bean;
                }
				interceptor = new GlobalTransactionalInterceptor(failureHandlerHook);
            }
            if (!AopUtils.isAopProxy(bean)) {
    
    
                bean = super.wrapIfNecessary(bean, beanName, cacheKey);//调用spring AOP代理
            } else {
    
    
                AdvisedSupport advised = SpringProxyUtils.getAdvisedSupport(bean);
                Advisor[] advisor = buildAdvisors(beanName, getAdvicesAndAdvisorsForBean(null, null, null));
                for (Advisor avr : advisor) {
    
    
                    advised.addAdvisor(0, avr);
                }
            }
            PROXYED_SET.add(beanName);
            return bean;
        }
    }
}

bean:方法存在GlobalTransactional、GlobalLock注解的目标类。

3、GlobalTransactionalInterceptor

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);
    if (specificMethod != null && !specificMethod.getDeclaringClass().equals(Object.class)) {
    
    
        final Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
        final GlobalTransactional globalTransactionalAnnotation =
            getAnnotation(method, targetClass, GlobalTransactional.class);
        final GlobalLock globalLockAnnotation = getAnnotation(method, targetClass, GlobalLock.class);
        boolean localDisable = disable || (degradeCheck && degradeNum >= degradeCheckAllowTimes);
        if (!localDisable) {
    
    
            if (globalTransactionalAnnotation != null) {
    
    
                return handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
            } else if (globalLockAnnotation != null) {
    
    
                return handleGlobalLock(methodInvocation);
            }
        }
    }
    return methodInvocation.proceed();
}
private Object handleGlobalTransaction(final MethodInvocation methodInvocation,
    final GlobalTransactional globalTrxAnno) throws Throwable {
    
    
    boolean succeed = true;
    try {
    
    
        return transactionalTemplate.execute(new TransactionalExecutor() {
    
    
            @Override
            public Object execute() throws Throwable {
    
    
                return methodInvocation.proceed();
            }

            public String name() {
    
    
                String name = globalTrxAnno.name();
                if (!StringUtils.isNullOrEmpty(name)) {
    
    
                    return name;
                }
                return formatMethod(methodInvocation.getMethod());
            }

            @Override
            public TransactionInfo getTransactionInfo() {
    
    
                TransactionInfo transactionInfo = new TransactionInfo();
                transactionInfo.setTimeOut(globalTrxAnno.timeoutMills());
                transactionInfo.setName(name());
                transactionInfo.setPropagation(globalTrxAnno.propagation());
                Set<RollbackRule> rollbackRules = new LinkedHashSet<>();
                for (Class<?> rbRule : globalTrxAnno.rollbackFor()) {
    
    
                    rollbackRules.add(new RollbackRule(rbRule));
                }
                for (String rbRule : globalTrxAnno.rollbackForClassName()) {
    
    
                    rollbackRules.add(new RollbackRule(rbRule));
                }
                for (Class<?> rbRule : globalTrxAnno.noRollbackFor()) {
    
    
                    rollbackRules.add(new NoRollbackRule(rbRule));
                }
                for (String rbRule : globalTrxAnno.noRollbackForClassName()) {
    
    
                    rollbackRules.add(new NoRollbackRule(rbRule));
                }
                transactionInfo.setRollbackRules(rollbackRules);
                return transactionInfo;
            }
        });
    } catch (TransactionalExecutor.ExecutionException e) {
    
    
        TransactionalExecutor.Code code = e.getCode();
        switch (code) {
    
    
            case RollbackDone:
                throw e.getOriginalException();
            case BeginFailure:
                succeed = false;
                failureHandler.onBeginFailure(e.getTransaction(), e.getCause());
                throw e.getCause();
            case CommitFailure:
                succeed = false;
                failureHandler.onCommitFailure(e.getTransaction(), e.getCause());
                throw e.getCause();
            case RollbackFailure:
                failureHandler.onRollbackFailure(e.getTransaction(), e.getOriginalException());
                throw e.getOriginalException();
            case RollbackRetrying:
                failureHandler.onRollbackRetrying(e.getTransaction(), e.getOriginalException());
                throw e.getOriginalException();
            default:
                throw new ShouldNeverHappenException(String.format("Unknown TransactionalExecutor.Code: %s", code));
        }
    } finally {
    
    
        if (degradeCheck) {
    
    
            EVENT_BUS.post(new DegradeCheckEvent(succeed));
        }
    }
}

3.1、TransactionalTemplate

public Object execute(TransactionalExecutor business) throws Throwable {
    
    
    // 1 get transactionInfo  注解存在事务的相关信息
    TransactionInfo txInfo = business.getTransactionInfo();
    // 1.1 get or create a transaction  DefaultGlobalTransaction
    GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
    // 1.2 Handle the Transaction propatation and the branchType
    Propagation propagation = txInfo.getPropagation();
    SuspendedResourcesHolder suspendedResourcesHolder = null;
    try {
    
    
        switch (propagation) {
    
    
            ...//事务传播策略
        }
        try {
    
    
            triggerBeforeBegin();
            // 2. begin transaction
        	tx.begin(txInfo.getTimeOut(), txInfo.getName());//tx:DefaultGlobalTransaction
        	triggerAfterBegin();
            Object rs = null;
            try {
    
    
                // 3.执行业务代码目标方法
                rs = business.execute();
            } catch (Throwable ex) {
    
    
                // 4.the needed business exception to rollback.
                completeTransactionAfterThrowing(txInfo, tx, ex);
                throw ex;
            }
            // 5. everything is fine, commit.
            commitTransaction(tx);
            return rs;
        } finally {
    
    
            //6. clear
            triggerAfterCompletion();
            cleanUp();
        }
    } finally {
    
    
        tx.resume(suspendedResourcesHolder);
    }
}
  1. 步骤2主要是通过Netty实现的RPC框架远程获取分支事务ID【应用服务机器IP:PORT:事务唯一标识ID】。
  2. 步骤3真正触发业务代码目标方法,执行RM的本地事务。

3.2、DefaultGlobalTransaction获取分布式事务xid

public void begin(int timeout, String name) throws TransactionException {
    
    
    if (role != GlobalTransactionRole.Launcher) {
    
    
        ...
        return;
    }
    //DefaultTransactionManager
    xid = transactionManager.begin(null, null, name, timeout);
    status = GlobalStatus.Begin;
    RootContext.bind(xid);
}

3.3、DefaultTransactionManager

public String begin(String applicationId, String transactionServiceGroup, String name, int timeout){
    
    
    GlobalBeginRequest request = new GlobalBeginRequest();
    request.setTransactionName(name);
    request.setTimeout(timeout);
    //rpc调用TC服务中生成的分支事务ID【xid】 由于RM分布式部署所以存在负载均衡策略
    GlobalBeginResponse response = (GlobalBeginResponse) syncCall(request);
    return response.getXid();
}

GlobalLock注解说明

从执行过程和提交过程可以看出,既然开启全局事务 @GlobalTransactional注解可以在事务提交前,查询全局锁是否存在,那为什么 Seata 还要设计多处一个 @GlobalLock注解呢?

因为并不是所有的数据库操作都需要开启全局事务,而开启全局事务是一个比较重的操作,需要向 TC 发起开启全局事务等 RPC 过程,而@GlobalLock注解只会在执行过程中查询全局锁是否存在,不会去开启全局事务,因此在不需要全局事务,而又需要检查全局锁避免脏读脏写时,使用@GlobalLock注解是一个更加轻量的操作。

参考文章

猜你喜欢

转载自blog.csdn.net/qq_36851469/article/details/128870501