Seata源码解析8——GlobalTransactional注解

前言

之前我们过了一遍独立服务:事务协调者(TC)的部分源码,光看源码还是比较难深入理解的。后面我们直接从一个事务的流程来讲,把整个流程中用到的源码都过一遍。

整个事务开始之前,肯定就要从事务注解@GlobalTransactional开始了。

在讲注解的时候,我们会过一遍Spring AOP实现原理。

关系总览

和GlobalTransactional相关的有GlobalTransactionScanner、GlobalTransactionalInterceptor两个类

GlobalTransactionScanner从名字就能看出用于扫描所有有事务注解的方法。

GlobalTransactionalInterceptor是对应的Advices/Advisors

GlobalTransactionScanner中使用了GlobalTransactionalInterceptor

GlobalTransactionScanner继承的接口和抽象类

我们先看GlobalTransactionScanner

public class GlobalTransactionScanner extends AbstractAutoProxyCreator
  implements InitializingBean, ApplicationContextAware, DisposableBean

GlobalTransactionScanner继承了AbstractAutoProxyCreatorInitializingBeanApplicationContextAwareDisposableBean

这几个接口有什么用呢?看到这里,如果没有学习过Spring,可能会一脸懵逼,我们一个个来看:

继承了ApplicationContextAware这个接口的bean,需要实现一个方法:

void setApplicationContext(ApplicationContext applicationContext) throws BeansException

当spring启动完成后,会自动调用这个接口,把ApplicationContext给bean。也就是说,GlobalTransactionScanner天然能拿到Spring的上下文。

继承了InitializingBean接口,需要实现一个方法:

void afterPropertiesSet() throws Exception;

凡是继承该接口的类,在初始化bean的时候,当所有properties都设置完成后,会执行该方法。我们后面再统一看看这里面做了什么。

继承DisposableBean,需要实现一个方法:

void destroy() throws Exception;

和InitializingBean接口相反,这个是在销毁的时候会调用这个方法。

AbstractAutoProxyCreator就比较复杂了,它Spring实现AOP的一种方式。本质上是一个BeanPostProcessor,他在bean初始化之前,调用内部的createProxy方法,创建一个bean的AOP代理bean并返回。

但是它不是把所有的bean都增强,选取哪些bean做增强呢?选取的策略是根据getAdvicesAndAdvisorsForBean方法返回的Advices/Advisors来确定的。

看到这里,其实总体的逻辑基本就清晰了,GlobalTransactionScanner扫描有注解的bean,做AOP增强。

GlobalTransactionScanner

然后,我们来看看GlobalTransactionScannerd,它的构造方法中有几个参数,这些参数都是在xml配置文件里传的

public GlobalTransactionScanner(String applicationId, String txServiceGroup, int mode,

                FailureHandler failureHandlerHook) {
   

  setOrder(ORDER_NUM);

  setProxyTargetClass(true);

  this.applicationId = applicationId;

  this.txServiceGroup = txServiceGroup;

  this.mode = mode;

  this.failureHandlerHook = failureHandlerHook;

}

配置文件示例:

<bean class="io.seata.spring.annotation.GlobalTransactionScanner">

  <constructor-arg value="tcc-sample"/>

  <constructor-arg value="my_test_tx_group"/>

</bean>

默认的模式是AT+MT,默认的失败处理handler是DefaultFailureHandlerImpl

我们看其他的方法前,先回顾一下Spring中Bean的关键初始化过程

实例化 -> 属性注入 -> postProcessBeforeInitialization -> afterPropertiesSet/init方法 -> postProcessAfterInitialization

实例化:

singletonFactory.getObject()实例化Bean的时候,最终调用getEarlyBeanReference来实例化Bean,它的逻辑很简单,从缓存里取Bean,没有就初始化一个,然后调用wrapIfNecessary。这个方法看名字就知道,会判断是否需要包装这个Bean。GlobalTransactionScanner里就重写了这个方法,后面重点关注。

属性注入:

这一步和我们讲事务没关系,忽略。

后面三步postProcessBeforeInitialization、afterPropertiesSet、postProcessAfterInitialization:

每一步GlobalTransactionScanner都有重写,我们重点关注。

下面,我们开始按照顺序,讲解上面说的,GlobalTransactionScanner里重写的方法

wrapIfNecessary:

这里面做了两个事情,

1)根据配置判断,到底用的是TCC模式,还是其他模式,会放置不同的interceptor。这些interceptor会在getAdvicesAndAdvisorsForBean中返回。

2)如果Bean不是代理类,则走Spring默认的AOP的Wrap;否则调用getAdvicesAndAdvisorsForBean获取要使用的Advices/Advisors,其实就是用第一步中配置的interceptor。

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;
            //是否TCC
            if (TCCBeanParserUtils.isTccAutoProxy(bean, beanName, applicationContext)) {
   
                //TCC代理的Bean有 sofa:reference/dubbo:reference/本地TCC
              //使用TccActionInterceptor作为Advices/Advisors
                interceptor = new TccActionInterceptor(TCCBeanParserUtils.getRemotingDesc(beanName));
            } else {
   
                Class<?> serviceInterface = SpringProxyUtils.findTargetClass(bean);
                Class<?>[] interfacesIfJdk = SpringProxyUtils.findInterfaces(bean);

                if (!
  • 12
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值