SpringBoot中事务执行原理分析补充篇

简介: SpringBoot中事务执行原理分析补充篇

关联博文:

SpringBoot中事务执行原理分析(一)

SpringBoot中事务执行原理分析(二)

SpringBoot中事务执行原理分析(三)

SpringBoot中事务执行原理分析(四)

SpringBoot中事务执行原理分析(五)

SpringBoot中事务执行原理分析(六)

SpringBoot中事务执行原理分析补充篇

你认真研究过Spring中的@EnableTransactionManagement注解吗?



本文是对SpringBoot中事务执行原理分析(一)的补充说明,我们详细分析一下如何判断Advisor与我们的service是否匹配。

【1】几个核心类

在前文中我们提到了BeanFactoryTransactionAttributeSourceAdvisor,其包含了Advice用于对我们的service进行增强实现事务效果。

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
  @Nullable
  private TransactionAttributeSource transactionAttributeSource;
  private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
    @Override
    @Nullable
    protected TransactionAttributeSource getTransactionAttributeSource() {
      return transactionAttributeSource;
    }
  };
  //...
} 
//ProxyTransactionManagementConfiguration中定义了advicetransactionInterceptor
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
    TransactionAttributeSource transactionAttributeSource,
    TransactionInterceptor transactionInterceptor) {
  BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
  advisor.setTransactionAttributeSource(transactionAttributeSource);
  advisor.setAdvice(transactionInterceptor);
  if (this.enableTx != null) {
    advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
  }
  return advisor;
}



TransactionAttributeSourcePointcut 就是我们AOP概念中的pointcut,用于判断类/方法是否匹配。如下所示其还设置了ClassFilter为TransactionAttributeSourceClassFilter用于类级别的判断。

abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
  protected TransactionAttributeSourcePointcut() {
    setClassFilter(new TransactionAttributeSourceClassFilter());
  }
//...
} 


TransactionAttributeSource其是一个策略接口被TransactionInterceptor使用来检测元数据信息。在本文这里其实际是AnnotationTransactionAttributeSource,这个在ProxyTransactionManagementConfiguration这个配置类中有定义。

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
//空参构造,publicMethodsOnly默认为true
  return new AnnotationTransactionAttributeSource();
}


这里要特别注意publicMethodsOnly 属性与annotationParsers 属性。前者标明是否只允许public方法,后者则是注解解析器。

public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
// 默认为true,表示只允许public方法
  this.publicMethodsOnly = publicMethodsOnly;
  if (jta12Present || ejb3Present) {
    this.annotationParsers = new LinkedHashSet<>(4);
    this.annotationParsers.add(new SpringTransactionAnnotationParser());
    if (jta12Present) {
      this.annotationParsers.add(new JtaTransactionAnnotationParser());
    }
    if (ejb3Present) {
      this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
    }
  }
  else {
  //指定注解解析器
    this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
  }
}


SpringTransactionAnnotationParser主要作用就是用来解析事务注解信息(@Transactional)。

【2】Advisor是如何匹配我们的service呢?

在AopUtils的findAdvisorsThatCanApply会对找到的Advisor进行逐一判断,鉴定其是否适用于我们的service。

如下所示在AopUtils的canApply方法中首先使用ClassFilter进行判断,然后获取到MethodMatcher 对class和method进行遍历循环判断。

public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {
  Assert.notNull(pc, "Pointcut must not be null");
  // 首先使用classFilter进行判断
  if (!pc.getClassFilter().matches(targetClass)) {
    return false;
  }
//获取到MethodMatcher 
  MethodMatcher methodMatcher = pc.getMethodMatcher();
  if (methodMatcher == MethodMatcher.TRUE) {
    // No need to iterate the methods if we're matching any method anyway...
    return true;
  }
//判断是否为引入方法匹配器
  IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
  if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
    introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
  }
//获取到目标类、超类
  Set<Class<?>> classes = new LinkedHashSet<>();
  if (!Proxy.isProxyClass(targetClass)) {
    classes.add(ClassUtils.getUserClass(targetClass));
  }
  classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
//对目标类与超类的所有方法进行遍历、判断
  for (Class<?> clazz : classes) {
    Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
    for (Method method : methods) {
      if (introductionAwareMethodMatcher != null ?
          introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions) :
          methodMatcher.matches(method, targetClass)) {
        return true;
      }
    }
  }
  return false;
}


① 类级别的判断

也就是下面这句代码, 前面我们提到过TransactionAttributeSourcePointcut中的classFilter是TransactionAttributeSourceClassFilter

pc.getClassFilter().matches(targetClass)


其是TransactionAttributeSourcePointcut的成员内部类(非静态内部类),我们看下其matches方法:

@Override
public boolean matches(Class<?> clazz) {
  if (TransactionalProxy.class.isAssignableFrom(clazz) ||
      PlatformTransactionManager.class.isAssignableFrom(clazz) ||
      PersistenceExceptionTranslator.class.isAssignableFrom(clazz)) {
    return false;
  }
  TransactionAttributeSource tas = getTransactionAttributeSource();
  return (tas == null || tas.isCandidateClass(clazz));
}


也就是说如果是TransactionalProxy、PlatformTransactionManager或者PersistenceExceptionTranslator,直接返回false。否则判断TransactionAttributeSource 是否为null或者TransactionAttributeSource的isCandidateClass方法是否为true。


如下所示,其将会遍历持有的TransactionAnnotationParser ,触发其isCandidateClass方法。

//AnnotationTransactionAttributeSource#isCandidateClass
@Override
public boolean isCandidateClass(Class<?> targetClass) {
  for (TransactionAnnotationParser parser : this.annotationParsers) {
    if (parser.isCandidateClass(targetClass)) {
      return true;
    }
  }
  return false;
}


本文我们只有一个SpringTransactionAnnotationParser,我们继续看SpringTransactionAnnotationParser解析器的isCandidateClass方法。

@Override
public boolean isCandidateClass(Class<?> targetClass) {
  return AnnotationUtils.isCandidateClass(targetClass, Transactional.class);
}


其只是触发了AnnotationUtils的isCandidateClass方法,如下所示可以说基本对我们的service来说都返回true。

public static boolean isCandidateClass(Class<?> clazz, String annotationName) {
//如果注解名称以java.开头,直接返回true
  if (annotationName.startsWith("java.")) {
    return true;
  }
  //如果clazz.getName以java.开头或者是Ordered类型
  if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {
    return false;
  }
  //直接返回true
  return true;
}

② 方法级别的判断

OK,我们往下再看方法级别如何判断。这里触发的是TransactionAttributeSourcePointcut的matches方法。其获取到TransactionAttributeSource ,如果tas为null或者使用tas获取到的事务属性信息不为null,则返回true。

@Override
public boolean matches(Method method, Class<?> targetClass) {
  TransactionAttributeSource tas = getTransactionAttributeSource();
  return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

如下图所示,AbstractFallbackTransactionAttributeSource的computeTransactionAttribute

方法中首先会根据publicMethodsOnly属性和方法的修饰符进行判断,如果非public则直接返回null(默认情况下publicMethodsOnly=true)。

然后将会从当前类进行级联查找方法上的事务注解信息,也就是说你的service如果实现了接口,那么在接口的方法上添加@Transactional(rollbackFor = Exception.class)也是OK的。

如何获取方法上的注解信息呢,这里就用到了SpringTransactionAnnotationParser,其将会级联检索方法上的事务注解。获取到的事务注解信息如下所示:

8eb1b64b120543abbfa76f51dfee5c7f.png


确定了Advisor与我们的service匹配后,就可以为我们的service创建代理进行实现事务增强了。

目录
相关文章
|
2月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
41 0
|
16天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
23天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
81 14
|
2月前
|
Java Spring
SpringBoot自动装配的原理
在Spring Boot项目中,启动引导类通常使用`@SpringBootApplication`注解。该注解集成了`@SpringBootConfiguration`、`@ComponentScan`和`@EnableAutoConfiguration`三个注解,分别用于标记配置类、开启组件扫描和启用自动配置。
64 17
|
2月前
|
Java 容器
springboot自动配置原理
启动类@SpringbootApplication注解下,有三个关键注解 (1)@springbootConfiguration:表示启动类是一个自动配置类 (2)@CompontScan:扫描启动类所在包外的组件到容器中 (3)@EnableConfigutarion:最关键的一个注解,他拥有两个子注解,其中@AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中,@Import会导入一个自动配置文件选择器,他会去加载META_INF目录下的spring.factories文件,这个文件中存放很大自动配置类的全类名,这些类会根据元注解的装配条件生效,生效
|
3月前
|
Java Spring 容器
springboot @RequiredArgsConstructor @Lazy解决循环依赖的原理
【10月更文挑战第15天】在Spring Boot应用中,循环依赖是一个常见问题,当两个或多个Bean相互依赖时,会导致Spring容器陷入死循环。本文通过比较@RequiredArgsConstructor和@Lazy注解,探讨它们解决循环依赖的原理和优缺点。@RequiredArgsConstructor通过构造函数注入依赖,使代码更简洁;@Lazy则通过延迟Bean的初始化,打破创建顺序依赖。两者各有优势,需根据具体场景选择合适的方法。
142 4
|
4月前
|
Java 应用服务中间件 API
Vertx高并发理论原理以及对比SpringBoot
Vertx 是一个基于 Netty 的响应式工具包,不同于传统框架如 Spring,它的侵入性较小,甚至可在 Spring Boot 中使用。响应式编程(Reactive Programming)基于事件模式,通过事件流触发任务执行,其核心在于事件流 Stream。相比多线程异步,响应式编程能以更少线程完成更多任务,减少内存消耗与上下文切换开销,提高 CPU 利用率。Vertx 适用于高并发系统,如 IM 系统、高性能中间件及需要较少服务器支持大规模 WEB 应用的场景。随着 JDK 21 引入协程,未来 Tomcat 也将优化支持更高并发,降低响应式框架的必要性。
Vertx高并发理论原理以及对比SpringBoot
|
3月前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
750 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
3月前
|
XML Java 应用服务中间件
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
【Spring】运行Spring Boot项目,请求响应流程分析以及404和500报错
280 2
|
3月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
208 1