声明式事务源码分析之EnableTransactionManagement

上节我们通过简单的案例来熟悉了spring注解版的声明式事务的开发,其实大家可以分别测一下,当我们不配置事务管理以及不贴注解EnableTransactionManagement时我们执行逻辑时是否会插入记录到数据库中,答案不行的,注解EnableTransactionManagement的主要目的是开启事务的功能,接下来的学习我们来围绕它进行

EnableTransactionManagement

点进去之后发现此注解位于org.springframework.transaction.annotation包下,具体代码片段如下:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
boolean proxyTargetClass() default false;

AdviceMode mode() default AdviceMode.PROXY;

int order() default 2147483647;

}

看到上述的代码我相信大家都不陌生,spring 的注解开发的套路,还是给我们的容器中导入一个组件【TransactionManagementConfigurationSelector】,接下来的核心就是它了

TransactionManagementConfigurationSelector

简单的说这个组件的作用是作为一个事务配置管理的选择器来出现帮助我们都做了什么事,方法进去我们发下如下的代码片段:

 protected String[] selectImports(AdviceMode adviceMode) {
    switch(adviceMode) {
    case PROXY:
        return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
    case ASPECTJ:
        return new String[]{this.determineTransactionAspectClass()};
    default:
        return null;
    }
}

其中通过传入的参数判断你到底是那种类型的,并为我们导入其对应的组件,我们这里是PROXY此类型的,为啥这么肯定了,在我们的EnableTransactionManagement 注解类中默认的就是它,大家可以在开头的代码片段中看到,是PROXY类型,这里帮我们导入的是AutoProxyRegistrar和ProxyTransactionManagementConfiguration这两个组件,分别来看:

AutoProxyRegistrar

该类实现了ImportBeanDefinitionRegistrar接口,也就是说其主要的作用是帮我们给容器注册其组件,接下来我们通过方法#registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) 来看帮我们注册的具体是那个组件

  • 1.首先通过如下的代码操作获取当前的当前容器的类型【AdviceMode:属于JDK的代理】
Object mode = candidate.get("mode");

前面我们已经知道了是PROXY类型的,所以接着看如下的代码片段:

 Object proxyTargetClass = candidate.get("proxyTargetClass");

 if (mode == AdviceMode.PROXY) {
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean)proxyTargetClass) {
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }

这里有两个判断,来看下:

  • 如果当前获取到了有proxyTargetClass【代理目标对象】时,会去执行方法AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry),很显然我们这里是不会调用的,在我们的注解类EnableTransactionManagement中proxyTargetClass的获取默认就是false,代码如下:
 boolean proxyTargetClass() default false;

所以我们直接来分析方法AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);

  @Nullable
  public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry) {
    return registerAutoProxyCreatorIfNecessary(registry, (Object)null);
}

@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
    return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

从上面的代码我们可以看到的是AutoProxyRegistrar帮我们想容器注册了一个InfrastructureAdvisorAutoProxyCreator【基础的自动代理增强创建器】,看到这个是不是跟我们Aop中【AspectJAwareAdvisorAutoProxyCreator】这个有点相似,其实质是一样的,只不过是事务中帮我们注册的是InfrastructureAdvisorAutoProxyCreator此类型的,我们看看它的作用:

InfrastructureAdvisorAutoProxyCreator

该类位于org.springframework.aop.framework.autoproxy包下,其继承实现关系如下图所示:

InfrastructureAdvisorAutoProxyCreator.png

不难发现InfrastructureAdvisorAutoProxyCreator实质也是一个【InstantiationAwareBeanPostProcessor】类型的后置处理器,那作为后置处理器的话,我们已经清楚的知道了它的作用:

  • 帮助我们完成对象的创建

  • 将创建完成的对象进行包装------> 返回其对应的代理对象

  • 获取拦截器链并进行相应的转化为一个个的拦截器

  • 利用拦截器机制进行链式的执行我们的目标方法

下面的代码是具体的注册过程:

   @Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    if (registry.containsBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator")) {
        BeanDefinition apcDefinition = registry.getBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator");
        if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
            int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
            int requiredPriority = findPriorityForClass(cls);
            if (currentPriority < requiredPriority) {
                apcDefinition.setBeanClassName(cls.getName());
            }
        }

        return null;
    } else {
        RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
        beanDefinition.setSource(source);
        beanDefinition.getPropertyValues().add("order", -2147483648);
        beanDefinition.setRole(2);
        registry.registerBeanDefinition("org.springframework.aop.config.internalAutoProxyCreator", beanDefinition);
        return beanDefinition;
    }
}

上述就是AutoProxyRegistrar组件帮我们所做的事,接下来我们来看看另外一个组件

ProxyTransactionManagementConfiguration

该类位于org.springframework.transaction.annotation包下,其实质也是一个配置类,该容器注册一些组件,这些组件有 transactionAdvisor 【事务增强器】和transactionInterceptor【事务拦截器】 ,具体注册的逻辑代码如下:

  • transactionAdvisor 【事务增强器】
  @Bean(
    name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
)
@Role(2)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor) {
    BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
    advisor.setTransactionAttributeSource(transactionAttributeSource);
    advisor.setAdvice(transactionInterceptor);
    if (this.enableTx != null) {
        advisor.setOrder((Integer)this.enableTx.getNumber("order"));
    }

    return advisor;
}
  • transactionInterceptor【事务拦截器】
@Bean
@Role(2)
public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) {
    TransactionInterceptor interceptor = new TransactionInterceptor();
    interceptor.setTransactionAttributeSource(transactionAttributeSource);
    if (this.txManager != null) {
        interceptor.setTransactionManager(this.txManager);
    }

    return interceptor;
}

其中在注册组件的过程中我们发现会有这样一个属性TransactionAttributeSource【事务属性源】,同样也是注册进来的

 @Bean
@Role(2)
public TransactionAttributeSource transactionAttributeSource() {
    return new AnnotationTransactionAttributeSource();
}

进去方法来到AnnotationTransactionAttributeSource类【事务注解的属性】,其中方法#AnnotationTransactionAttributeSource(boolean publicMethodsOnly)需要我们注意一点

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
    this.publicMethodsOnly = publicMethodsOnly;
    if (!jta12Present && !ejb3Present) {
        this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
    } else {
        this.annotationParsers = new LinkedHashSet(4);
        this.annotationParsers.add(new SpringTransactionAnnotationParser());
        if (jta12Present) {
            this.annotationParsers.add(new JtaTransactionAnnotationParser());
        }

        if (ejb3Present) {
            this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
        }
    }

}

方法主要是当前是那种类型的事务并进行解释其对应的事务注解信息,当然这里用的是spring的自己的事务,也就是如下代码:

 if (!jta12Present && !ejb3Present) {
        this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
    } else {
        this.annotationParsers = new LinkedHashSet(4);
        this.annotationParsers.add(new SpringTransactionAnnotationParser());

接着我们看到是通过SpringTransactionAnnotationParser【事务注解解析器】来帮助我们解析具体的注解信息,进去来到类SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotationAttributes attributes)方法来完成事务注解的解析过程,解析之前还是有一步重要的动作来看方法

@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
    AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
            element, Transactional.class, false, false);
    if (attributes != null) {
        return parseTransactionAnnotation(attributes);
    }
    else {
        return null;
    }
}

这段代码很简单,无非就是先拿到我们的注解类Transactional【事务注解】然后封装成一个注解属性【AnnotationAttributes 】,接着调用我们的具体解析方法,Transactional具体都有哪些属性我们来看看:

public @interface Transactional {
@AliasFor("transactionManager")
String value() default "";

@AliasFor("value")
String transactionManager() default "";

Propagation propagation() default Propagation.REQUIRED;

Isolation isolation() default Isolation.DEFAULT;

int timeout() default -1;

boolean readOnly() default false;

Class<? extends Throwable>[] rollbackFor() default {};

String[] rollbackForClassName() default {};

Class<? extends Throwable>[] noRollbackFor() default {};

String[] noRollbackForClassName() default {};

}

上述的这些属性我们都是可以配置的如:

@Service
public class UserService {

@Resource
private UserDao userDao;
@Transactional(propagation = Propagation.REQUIRED ,isolation = Isolation.DEFAULT,timeout = 1)
public void insert(){
    userDao.insert();
    System.out.println("插入成功....");

    int i = 10 / 0;
}

感兴趣的可以自己玩玩,既然我们已经到AnnotationTransactionAttributeSource的作用,回到我们分析的入口类ProxyTransactionManagementConfiguration

  • 我们在方法#transactionAdvisor(TransactionAttributeSource transactionAttributeSource, TransactionInterceptor transactionInterceptor)中

  • 给容器中注册了一个BeanFactoryTransactionAttributeSourceAdvisor【事务增强器】

  • 接着事务增强器保存我们前面分析的事务注解信息

  • 保存事务拦截器到事务增强器中

  • 最后进行排序操作

期间我们用到了事务拦截器,那么我们来看看这事务拦截器的作用

TransactionInterceptor

该类位于org.springframework.transaction.interceptor包下,发下该类实现了MethodInterceptor接口,代码片段如下:

public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}

还记得我们在Aop目标方法分析时,有一步就是将每一个拦截器包装成一个MethodInterceptor类型的拦截器,其实看到这里我们的事务拦截器的跟Aop的原理是类似的,接着回到我们的TransactionInterceptor类中#invoke(MethodInvocation invocation)方法

 @Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
    Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
    Method var10001 = invocation.getMethod();
    invocation.getClass();
    return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}

其中方法#invokeWithinTransaction(....)执行目标类的,进去我们来到l类TransactionAspectSupport中的#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation)方法,具体看看方法做了哪些处理:

  • 首先获取事务注解属性
 TransactionAttributeSource tas = this.getTransactionAttributeSource();
    TransactionAttribute txAttr = tas != null ? tas.getTransactionAttribute(method, targetClass) : null;

上述只是做铺垫,接下来我们来看重头戏,是如何获取我们的事务管理器的,代码片段如下:

TransactionManager tm = this.determineTransactionManager(txAttr);

继续跟踪代码来到方法#determineTransactionManager(@Nullable TransactionAttribute txAttr)

 @Nullable
protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
    if (txAttr != null && this.beanFactory != null) {
        String qualifier = txAttr.getQualifier();
        if (StringUtils.hasText(qualifier)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, qualifier);
        } else if (StringUtils.hasText(this.transactionManagerBeanName)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
        } else {
            TransactionManager defaultTransactionManager = this.getTransactionManager();
            if (defaultTransactionManager == null) {
                defaultTransactionManager = (TransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
                if (defaultTransactionManager == null) {
                    defaultTransactionManager = (TransactionManager)this.beanFactory.getBean(TransactionManager.class);
                    this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
                }
            }

            return defaultTransactionManager;
        }
    } else {
        return this.getTransactionManager();
    }
}

上述代码主要的操作是通过不同的方式去获取我们的事务管理器实例,分别来看:

  • 1.通过注解 @Qualifier去获取
 String qualifier = txAttr.getQualifier();
        if (StringUtils.hasText(qualifier)) {
            return this.determineQualifiedTransactionManager(this.beanFactory, qualifier);

方法进去来到具体是如何实现的过程:

private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
    PlatformTransactionManager txManager = asPlatformTransactionManager(this.transactionManagerCache.get(qualifier));
    if (txManager == null) {
        txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType(
                beanFactory, PlatformTransactionManager.class, qualifier);
        this.transactionManagerCache.putIfAbsent(qualifier, txManager);
    }
    return txManager;
}
  • 方式二:通过bean的名字去获取
  else {
            TransactionManager defaultTransactionManager = this.getTransactionManager();
            if (defaultTransactionManager == null) {
                defaultTransactionManager = (TransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
                if (defaultTransactionManager == null) {
                    defaultTransactionManager = (TransactionManager)this.beanFactory.getBean(TransactionManager.class);
                    this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
                }
            }

很显然我们是自己配置的事务管理器,所以是通过方式二的去获取事务管理器的,既然我们了解了事务管理器的获取过程,回到我们的方法#invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, TransactionAspectSupport.InvocationCallback invocation)接着看:

  • 接着获取我们的PlatformTransactionManager
PlatformTransactionManager ptm = this.asPlatformTransactionManager(tm);

前提是之前没有添加指定任何transactionmanger最终会从容器中按照类型获取一个PlatformTransactionManager

  • 最后执行我们的目标方法
    1. 如果是正常的情况下直接提交事务
 private Mono<Void> commitTransactionAfterReturning(@Nullable TransactionAspectSupport.ReactiveTransactionInfo txInfo) {
        if (txInfo != null && txInfo.getReactiveTransaction() != null) {
            if (TransactionAspectSupport.this.logger.isTraceEnabled()) {
                TransactionAspectSupport.this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
            }

            return txInfo.getTransactionManager().commit(txInfo.getReactiveTransaction());
        } else {
            return Mono.empty();
        }
    }

2.如果有异常的话,进行事务回滚

private Mono<Void> completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.ReactiveTransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getReactiveTransaction() != null) {
            if (TransactionAspectSupport.this.logger.isTraceEnabled()) {
                TransactionAspectSupport.this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }

            return txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex) ? txInfo.getTransactionManager().rollback(txInfo.getReactiveTransaction()).onErrorMap((ex2) -> {
                TransactionAspectSupport.this.logger.error("Application exception overridden by rollback exception", ex);
                if (ex2 instanceof TransactionSystemException) {
                    ((TransactionSystemException)ex2).initApplicationException(ex);
                }

                return ex2;
            }) : txInfo.getTransactionManager().commit(txInfo.getReactiveTransaction()).onErrorMap((ex2) -> {
                TransactionAspectSupport.this.logger.error("Application exception overridden by commit exception", ex);
                if (ex2 instanceof TransactionSystemException) {
                    ((TransactionSystemException)ex2).initApplicationException(ex);
                }

                return ex2;
            });
        } else {
            return Mono.empty();
        }
    }

可以发现的是,不管是事务提交还是回滚操作,都是通过我们的事务管理器来完成,到这里我们的声明式事务的相关源码分析已完成

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352