Spring事务专题之七、@Transaction事务源码解析

大家好,今天咱们通过源码来了解一下spring中@Transaction事务的原理。

在这里插播两句,整个系列前后知识是有依赖的,大家最好按顺序阅读,这样不会出现无法理解的情况,若跳着读,可能会比较懵。。。

1、环境

  1. jdk1.8
  2. Spring版本:5.2.3.RELEASE
  3. mysql5.7

2、@Transaction 事务的用法

咱们先来回顾一下,@Transaction 事务的用法,特别简单,2个步骤

1、在需要让spring管理事务的方法上添加 @Transaction 注解

2、在spring配置类上添加 @EnableTransactionManagement 注解,这步特别重要,别给忘了,有了这个注解之后,@Trasaction标注的方法才会生效。

3、@Transaction事务原理

原理比较简单,内部是通过spring aop的功能,通过拦截器拦截 @Transaction 方法的执行,在方法前后添加事务的功能。

4、@EnableTransactionManagement注解作用

@EnableTransactionManagement注解会开启spring自动管理事务的功能,有了这个注解之后,spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让spring来管理事务,即判断bean中是否有@Transaction注解,判断规则如下

1、一直沿着当前bean的类向上找,先从当前类中,然后父类、父类的父类,当前类的接口、接口父接口,父接口的父接口,一直向上找,一下这些类型上面是否有 @Transaction注解

2、类的任意public方法上面是否有@Transaction注解

如果bean满足上面任意一个规则,就会被spring容器通过aop的方式创建代理,代理中会添加一个拦截器

  1. org.springframework.transaction.interceptor.TransactionInterceptor

TransactionInterceptor 拦截器是关键,它会拦截@Trasaction方法的执行,在方法执行前后添加事务的功能,这个拦截器中大部分都是编程式事务的代码,若 编程式事务的源码 大家看懂了,这个拦截器源码看起来就是小儿科了。

5、@EnableTransactionManagement源码解析

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @Import(TransactionManagementConfigurationSelector.class) //@1
  5. public @interface EnableTransactionManagement {
  6. // 是基于类的代理(cglib),还是基于接口的代理(jdk动态代理),默认为false,表示是基于jdk动态代理
  7. boolean proxyTargetClass() default false;
  8. //通知的模式,默认是通过aop的方式
  9. AdviceMode mode() default AdviceMode.PROXY;
  10. // 我们知道这个注解的功能最终是通过aop的方式来实现的,对bean创建了一个代理,代理中添加了一个拦截器
  11. // 当代理中还有其他拦截器的是时候,可以通过order这个属性来指定事务拦截器的顺序
  12. // 默认值是 LOWEST_PRECEDENCE = Integer.MAX_VALUE,拦截器的执行顺序是order升序
  13. int order() default Ordered.LOWEST_PRECEDENCE;
  14. }

注意@1这个代码

  1. @Import(TransactionManagementConfigurationSelector.class)

用到了@Import注解,对这个注解不熟悉的可以看一下Spring系列第18篇:@import详解(bean批量注册),这个注解的value是TransactionManagementConfigurationSelector,看一下这个类的源码,重点是他的selectImports方法,这个方法会返回一个类名数组,spring容器启动过程中会自动调用这个方法,将这个方法指定的类注册到spring容器中;方法的参数是AdviceMode,这个就是@EnableTransactionManagement注解中mode属性的值,默认是PROXY,所以会走到@1代码处

  1. public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
  2. @Override
  3. protected String[] selectImports(AdviceMode adviceMode) {
  4. switch (adviceMode) {
  5. case PROXY: //@1
  6. return new String[] {AutoProxyRegistrar.class.getName(),
  7. ProxyTransactionManagementConfiguration.class.getName()};
  8. case ASPECTJ:
  9. return new String[] {determineTransactionAspectClass()};
  10. default:
  11. return null;
  12. }
  13. }
  14. }

最终会在spirng容器中注册下面这2个bean

  1. AutoProxyRegistrar
  2. ProxyTransactionManagementConfiguration

下面来看一下这2个类的代码。

AutoProxyRegistrar

这个类实现了ImportBeanDefinitionRegistrar接口,这个接口中有个方法registerBeanDefinitions,spring容器在启动过程中会调用这个方法,开发者可以在这个方法中做一些bean注册的事情,而AutoProxyRegistrar在这个方法中主要做的事情就是下面@1的代码,大家可以点进去看看,这里我就不点进去了,这个代码的作用就是在容器中做了一个非常关键的bean:InfrastructureAdvisorAutoProxyCreator,这个类之前在aop中介绍过,是bean后置处理器,会拦截所有bean的创建,对符合条件的bean创建代理。

  1. public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
  2. @Override
  3. public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
  4. boolean candidateFound = false;
  5. Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
  6. for (String annType : annTypes) {
  7. AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
  8. if (candidate == null) {
  9. continue;
  10. }
  11. Object mode = candidate.get("mode");
  12. Object proxyTargetClass = candidate.get("proxyTargetClass");
  13. if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
  14. Boolean.class == proxyTargetClass.getClass()) {
  15. candidateFound = true;
  16. if (mode == AdviceMode.PROXY) {
  17. AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);//@1
  18. if ((Boolean) proxyTargetClass) {
  19. AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
  20. return;
  21. }
  22. }
  23. }
  24. }
  25. }
  26. }

说的简单点:AutoProxyRegistrar的作用就是启用spring aop的功能,对符合条件的bean创建代理。

ProxyTransactionManagementConfiguration

  1. @Configuration(proxyBeanMethods = false)
  2. public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
  3. //注册bean:事务顾问(spring aop中拦截器链就是一个个的Advisor对象)
  4. @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
  5. @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  6. public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
  7. TransactionAttributeSource transactionAttributeSource,
  8. TransactionInterceptor transactionInterceptor) {
  9. BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
  10. advisor.setTransactionAttributeSource(transactionAttributeSource);
  11. //设置事务拦截器
  12. advisor.setAdvice(transactionInterceptor);
  13. if (this.enableTx != null) {
  14. //设置aop中事务拦截器的顺序
  15. advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
  16. }
  17. return advisor;
  18. }
  19. //注册bean:TransactionAttributeSource,TransactionAttributeSource用来获取获取事务属性配置信息:TransactionAttribute
  20. @Bean
  21. @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  22. public TransactionAttributeSource transactionAttributeSource() { //@1
  23. return new AnnotationTransactionAttributeSource();
  24. }
  25. //注册bean:事务拦截器
  26. @Bean
  27. @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
  28. public TransactionInterceptor transactionInterceptor(
  29. TransactionAttributeSource transactionAttributeSource) {
  30. TransactionInterceptor interceptor = new TransactionInterceptor();
  31. interceptor.setTransactionAttributeSource(transactionAttributeSource);
  32. //拦截器中设置事务管理器,txManager可以为空
  33. if (this.txManager != null) {
  34. interceptor.setTransactionManager(this.txManager);
  35. }
  36. return interceptor;
  37. }
  38. }

是个配置类,代码比较简单,注册了3个bean,最重要的一点就是添加了事务事务拦截器:TransactionInterceptor。

AutoProxyRegistrar负责启用aop的功能,而ProxyTransactionManagementConfiguration负责在aop中添加事务拦截器,二者结合起来的效果就是:对@Transaction标注的bean创建代理对象,代理对象中通过TransactionInterceptor拦截器来实现事务管理的功能。

再看下代码@1,注册了一个TransactionAttributeSource类型的bean

TransactionAttributeSource接口源码:

  1. public interface TransactionAttributeSource {
  2. /**
  3. * 确定给定的类是否是这个TransactionAttributeSource元数据格式中的事务属性的候选类。
  4. * 如果此方法返回false,则不会遍历给定类上的方法,以进行getTransactionAttribute内省。
  5. * 因此,返回false是对不受影响的类的优化,而返回true仅仅意味着类需要对给定类上的每个方法进行完全自省。
  6. **/
  7. default boolean isCandidateClass(Class<?> targetClass) {
  8. return true;
  9. }
  10. //返回给定方法的事务属性,如果该方法是非事务性的,则返回null。
  11. TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass);
  12. }

getTransactionAttribute方法用来获取指定方法上的事务属性信息TransactionAttribute,大家对TransactionDefinition比较熟悉吧,用来配置事务属性信息的,而TransactionAttribute继承了TransactionDefinition接口,源码如下,而TransactionAttribute中新定义了2个方法,一个方法用来指定事务管理器bean名称的,一个用来判断给定的异常是否需要回滚事务

  1. public interface TransactionAttribute extends TransactionDefinition {
  2. //事务管理器的bean名称
  3. @Nullable
  4. String getQualifier();
  5. //判断指定的异常是否需要回滚事务
  6. boolean rollbackOn(Throwable ex);
  7. }

TransactionAttributeSource接口有个实现类AnnotationTransactionAttributeSource,负责将@Transaction解析为TransactionAttribute对象,大家可以去这个类中设置一下断点看一下@Transaction注解查找的顺序,这样可以深入理解@Transaction放在什么地方才会让事务起效。

AnnotationTransactionAttributeSource内部最会委托给SpringTransactionAnnotationParser#parseTransactionAnnotation方法来解析@Transaction注解,进而得到事务属性配置信息:RuleBasedTransactionAttribute,代码如下:

  1. org.springframework.transaction.annotation.SpringTransactionAnnotationParser
  2. protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
  3. RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
  4. Propagation propagation = attributes.getEnum("propagation");
  5. rbta.setPropagationBehavior(propagation.value());
  6. Isolation isolation = attributes.getEnum("isolation");
  7. rbta.setIsolationLevel(isolation.value());
  8. rbta.setTimeout(attributes.getNumber("timeout").intValue());
  9. rbta.setReadOnly(attributes.getBoolean("readOnly"));
  10. rbta.setQualifier(attributes.getString("value"));
  11. //回滚规则
  12. List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
  13. for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
  14. rollbackRules.add(new RollbackRuleAttribute(rbRule));
  15. }
  16. for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
  17. rollbackRules.add(new RollbackRuleAttribute(rbRule));
  18. }
  19. for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
  20. rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
  21. }
  22. for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
  23. rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
  24. }
  25. rbta.setRollbackRules(rollbackRules);
  26. return rbta;
  27. }

下面来看重点了事务拦截器。

6、TransactionInterceptor

负责拦截@Transaction方法的执行,在方法执行之前开启spring事务,方法执行完毕之后提交或者回滚事务。

在讲这个类的源码之前,先提几个问题,大家带着问题去看代码,理解更深一些。

1、事务管理器是如何获取的?

2、什么情况下事务会提交?

3、什么异常会导致事务回滚?

6.1、invokeWithinTransaction方法

这个方法是事务拦截器的入口,需要spring管理事务的业务方法会被这个方法拦截,大家可以设置断点跟踪一下

  1. protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
  2. final InvocationCallback invocation) throws Throwable {
  3. TransactionAttributeSource tas = getTransactionAttributeSource();
  4. //@6-1:获取事务属性配置信息:通过TransactionAttributeSource.getTransactionAttribute解析@Trasaction注解得到事务属性配置信息
  5. final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
  6. //@6-2:获取事务管理器
  7. final TransactionManager tm = determineTransactionManager(txAttr);
  8. //将事务管理器tx转换为 PlatformTransactionManager
  9. PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
  10. if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
  11. // createTransactionIfNecessary内部,这里就不说了,内部主要就是使用spring事务硬编码的方式开启事务,最终会返回一个TransactionInfo对象
  12. TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
  13. // 业务方法返回值
  14. Object retVal;
  15. try {
  16. //调用aop中的下一个拦截器,最终会调用到业务目标方法,获取到目标方法的返回值
  17. retVal = invocation.proceedWithInvocation();
  18. }
  19. catch (Throwable ex) {
  20. //6-3:异常情况下,如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
  21. completeTransactionAfterThrowing(txInfo, ex);
  22. throw ex;
  23. }
  24. finally {
  25. //清理事务信息
  26. cleanupTransactionInfo(txInfo);
  27. }
  28. //6-4:业务方法返回之后,只需事务提交操作
  29. commitTransactionAfterReturning(txInfo);
  30. //返回执行结果
  31. return retVal;
  32. }
  33. }

6.2、获取事务管理器

  1. //@6-2:获取事务管理器
  2. final TransactionManager tm = determineTransactionManager(txAttr);

determineTransactionManager源码如下:

  1. org.springframework.transaction.interceptor.TransactionAspectSupport#determineTransactionManager
  2. protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
  3. // txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器
  4. if (txAttr == null || this.beanFactory == null) {
  5. return getTransactionManager();
  6. }
  7. //qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称
  8. String qualifier = txAttr.getQualifier();
  9. if (StringUtils.hasText(qualifier)) {
  10. //从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean
  11. return determineQualifiedTransactionManager(this.beanFactory, qualifier);
  12. }
  13. else if (StringUtils.hasText(this.transactionManagerBeanName)) {
  14. //从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean
  15. return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
  16. }
  17. else {
  18. //最后通过类型TransactionManager在spring容器中找事务管理器
  19. TransactionManager defaultTransactionManager = getTransactionManager();
  20. if (defaultTransactionManager == null) {
  21. defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
  22. if (defaultTransactionManager == null) {
  23. defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class);
  24. this.transactionManagerCache.putIfAbsent(
  25. DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
  26. }
  27. }
  28. return defaultTransactionManager;
  29. }
  30. }

从上面可知,事务管理器的查找顺序:

1、先看@Transactional中是否通过value或者transactionManager指定了事务管理器

2、TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器

3、如果上面2种都没有,将从spring容器中查找TransactionManager类型的事务管理器

6.3、异常情况下,如何走?

  1. try{
  2. //....
  3. }catch (Throwable ex) {
  4. //6-3:异常情况下,如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置
  5. completeTransactionAfterThrowing(txInfo, ex);
  6. throw ex;
  7. }

源码中可以看出,发生异常了会进入completeTransactionAfterThrowing方法,completeTransactionAfterThrowing 源码如下

  1. protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
  2. if (txInfo != null && txInfo.getTransactionStatus() != null) {
  3. //@6-3-1:判断事务是否需要回滚
  4. if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
  5. //通过事务管理器回滚事务
  6. txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
  7. }
  8. else {
  9. //通过事务管理器提交事务
  10. txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  11. }
  12. }
  13. }

注意上面的@6-3-1代码,判断事务是否需要回滚,调用的是transactionAttribute.rollbackOn(ex),最终会进入下面这个方法内部

  1. org.springframework.transaction.interceptor.RuleBasedTransactionAttribute#rollbackOn
  2. public boolean rollbackOn(Throwable ex) {
  3. RollbackRuleAttribute winner = null;
  4. int deepest = Integer.MAX_VALUE;
  5. //@Trasaction中可以通过rollbackFor指定需要回滚的异常列表,通过noRollbackFor属性指定不需要回滚的异常
  6. //根据@Transactional中指定的回滚规则判断ex类型的异常是否需要回滚
  7. if (this.rollbackRules != null) {
  8. for (RollbackRuleAttribute rule : this.rollbackRules) {
  9. int depth = rule.getDepth(ex);
  10. if (depth >= 0 && depth < deepest) {
  11. deepest = depth;
  12. winner = rule;
  13. }
  14. }
  15. }
  16. //若@Transactional注解中没有匹配到,这走默认的规则,将通过super.rollbackOn来判断
  17. if (winner == null) {
  18. return super.rollbackOn(ex);
  19. }
  20. return !(winner instanceof NoRollbackRuleAttribute);
  21. }

super.rollbackOn(ex)源码如下,可以看出默认情况下,异常类型是RuntimeException或者Error的情况下,事务才会回滚

  1. @Override
  2. public boolean rollbackOn(Throwable ex) {
  3. return (ex instanceof RuntimeException || ex instanceof Error);
  4. }

6.4、没有异常如何走?

  1. //6-4:业务方法返回之后,只需事务提交操作
  2. commitTransactionAfterReturning(txInfo);

没有异常的情况下会进入commitTransactionAfterReturning方法,commitTransactionAfterReturning源码如下,比较简单,就是调用事务管理器的commit方法提交事务

  1. protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
  2. if (txInfo != null && txInfo.getTransactionStatus() != null) {
  3. txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
  4. }
  5. }

源码解析的差不多了,建议大家设置断点跟踪一下,加深对事务原理的理解。

7、重点回顾

1、使用@Transaction的时候,一定别忘记@EnableTransactionManagement注解,否则事务不起效

2、@Transaction的功能主要是通过aop来实现的,关键代码在TransactionInterceptor拦截器中

3、默认情况下,事务只会在 RuntimeException 或 Error 异常下回滚,可以通@Transaction来配置其他需要回滚或不需要回滚的异常类型

8、课堂讨论

下面代码的执行结果是什么?为什么?

  1. @Component
  2. public class ServiceA {
  3. @Autowired
  4. ServiceB serviceB;
  5. @Transactional
  6. public void m1() {
  7. try {
  8. serviceB.m2();
  9. } catch (Exception e) {
  10. e.printStackTrace();
  11. }
  12. "insert into t_user (name) values ('张三')";
  13. }
  14. }
  15. @Component
  16. public class ServiceB {
  17. @Transactional
  18. public void m2() {
  19. "insert into t_user (name) values ('李四')";
  20. throw new RuntimeException("手动抛出异常!");
  21. }
  22. }

欢迎留言和我分享你的想法。如果有收获,也欢迎你把这篇文章分享给你的朋友。

案例源码

  1. git地址:
  2. https://gitee.com/javacode2018/spring-series

本博客所有系列案例代码以后都会放到这个上面,大家watch一下,可以持续关注动态。

继续收门徒,月薪 4W 以下的可以来找我,4W 以上的靠你们自己的天赋了

最新资料

  1. 尚硅谷 Java 学科全套教程(总 207.77GB)
  2. 2021 最新版 Java 微服务学习线路图 + 视频
  3. 阿里技术大佬整理的《Spring 学习笔记.pdf》
  4. 阿里大佬的《MySQL 学习笔记高清.pdf》
  5. 2021 版 java 高并发常见面试题汇总.pdf
  6. Idea 快捷键大全.pdf

来源:http://www.itsoku.com/course/12/130
posted @ 2022-04-26 10:31  程序员小明1024  阅读(226)  评论(0编辑  收藏  举报