Spring系列28:如何深入解析@Transactional事务源码?

2026-05-27 16:041阅读0评论SEO资讯
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计4851个文字,预计阅读时间需要20分钟。

Spring系列28:如何深入解析@Transactional事务源码?

原文内容:本文内容+ @Transactional事务使用+ @EnableTransactionManagement详解+ @Transactional事务属性的解析+ TransactionInterceptor事务控制+声明式事务使用和原理声明式事务的主要步骤+ 使用@EnableTransactionManagement启用事务

改写后:本文介绍@EnableTransactionManagement的使用及事务控制原理,包括事务属性解析、TransactionInterceptor和声明式事务步骤。

本文内容
  1. @Transactional事务使用

  2. @EnableTransactionManagement 详解

  3. @Transactional事务属性的解析

  4. TransactionInterceptor 事务控制

声明式事务使用和原理 声明式的主要步骤
  1. 使用@EnableTransactionManagement启用Spring 事务管理支持
  2. 使用@Transactional标识需要事务的方法会自动开启事务
  3. 注入数据源和事务管理器

下面通过案例演示一下上面的效果。

案例
  1. 使用@EnableTransactionManagement启用Spring 事务管理支持,配置类上需要有@Configuration注解

    @Configuration @ComponentScan @EnableTransactionManagement public class AppConfig {}

  2. 使用@Transactional标识需要事务的方法会自动开启事务。addUser方法需要事务

    @Service public class UserService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void addUser() { System.out.println("执行前记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); jdbcTemplate.update("insert into t_user (name) values (?)", "xx"); jdbcTemplate.update("insert into t_user (name) values (?)", "oo"); System.out.println("执行后记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); } }

  3. 注入数据源和事务管理器

    @Configuration @ComponentScan @EnableTransactionManagement public class AppConfig { /** * 定义一个数据源 * @return */ @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(""); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.25.24:3306/xxx?characterEncoding=UTF-8"); dataSource.setUsername("root"); dataSource.setPassword("xxx"); return dataSource; } /** * 定义一个JdbcTemplate来执行sql * @param dataSource * @return */ @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } /** * 定义一个管理器 * @param dataSource * @return */ @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }

  4. 测试程序

    public class DeclarativeTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.addUser(); context.close(); } }

    输出结果如下:

    执行前记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}] 执行后记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}, {id=7, name=xx}, {id=8, name=oo}]

原理

@EnableTransactionManagement注解会开启Spring自动管理事务的功能。开启之后在Spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让Spring来管理事务,如果需要那么通过aop的方式创建代理对象。代理中会添加一个拦截器TransactionInterceptor,拦截@Trasaction标识方法的执行,在方法执行前后添加事务的功能。

Spring系列28:如何深入解析@Transactional事务源码?

下面进行源码分析,需要用到的前置只是是Spring Aop相关知识和编程式事务管理的知识,前面的文章有涉及,提前看一下。

@EnableTransactionManagement 详解

@EnableTransactionManagement 会开启Spring的事务管理功能,查看下源码。

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { /** * 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)。默认为false。 * 仅当mode()设置为AdviceMode.PROXY时适用。 */ boolean proxyTargetClass() default false; /** * 指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。 * 请注意,代理模式只允许通过代理拦截调用。同一类内的本地调用不会被拦截; * 在本地调用中,对这种方法的Transactional注释将被忽略,因为Spring的拦截器甚至不会在这样的运行时场景中起作用。 */ AdviceMode mode() default AdviceMode.PROXY; /** * 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE */ int order() default Ordered.LOWEST_PRECEDENCE; } 3个参数属性值

  • proxyTargetClass : 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)
  • mode:指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
  • order: 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE,最后处理事务拦截器。
TransactionManagementConfigurationSelector

重点是@Import(TransactionManagementConfigurationSelector.class),注入一些事务相关的bean到Spring容器中进行事务的管理控制。

根据EnableTransactionManagement的mode值选择应该使用AbstractTransactionManagementConfiguration的哪个实现。

package org.springframework.transaction.annotation; public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { /** * 此处是AdviceMode的作用,默认是用代理,另外一个是ASPECTJ */ @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: // @1 return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }

我们的mode是 AdviceMode.PROXY ,所以走@1位置,注入AutoProxyRegistrarProxyTransactionManagementConfiguration

AutoProxyRegistrar注入 InfrastructureAdvisorAutoProxyCreator

AutoProxyRegistrar的作用是注入一个InfrastructureAdvisorAutoProxyCreator,用于拦截bean的创建过程,为需要的事务控制的bean 创建代理对象,这个类非常关键,后面详细讲。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); // 遍历所有注解,找到有mode和proxyTargetClass的注解 for (String annType : annTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null) { continue; } Object mode = candidate.get("mode"); Object proxyTargetClass = candidate.get("proxyTargetClass"); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; if (mode == AdviceMode.PROXY) { // 注册aop InfrastructureAdvisorAutoProxyCreator 不展开 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); // 强制设置proxyTargetClass=true后面使用cglib if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } } } ProxyTransactionManagementConfiguration

@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @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; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }

ProxyTransactionManagementConfiguration 代理事务配置,注册事务需要用的一些类,而且Role=ROLE_INFRASTRUCTURE都是属于内部级别的,如下:

  • BeanFactoryTransactionAttributeSourceAdvisor 事务属性通知器,存放事务注解的方法相关的属性
  • TransactionAttributeSource事务属性源,就是事务注解的一些属性,也用来解析事务注解属性,实际是AnnotationTransactionAttributeSource
  • TransactionInterceptor事务拦截器,该类包含与Spring底层事务API的集成。TransactionInterceptor简单地以正确的顺序调用相关的超类方法,比如invokeWithinTransaction。这个类非常关键,负责事务相关的AOP增强的。
小结

EnableTransactionManagement注解的作用主要注入了InfrastructureAdvisorAutoProxyCreator负责拦截bean的创建过程为特定的bean创建代理对象,并通过TransactionInterceptor事务拦截器来实现方法的事务控制。

@Transactional 详解

该注解用于描述单个方法或类上的事务属性。在类级别,该注释作为默认值应用于声明类及其子类的所有方法。注意,类级别它并不适用于类层次结构上的父类,也就是父类方法需要在本地重新声明,以便参与子类级别的注释。

注解的属性的语义的具体信息,由 TransactionDefinitionTransactionAttribute 提供。

package org.springframework.transaction.annotation; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; /** * 用来确定目标事务管理器bean */ @AliasFor("value") String transactionManager() default ""; /** * 事务传播类型 */ Propagation propagation() default Propagation.REQUIRED; /** * 事务隔离级别 */ Isolation isolation() default Isolation.DEFAULT; /** * 事务超时 */ int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; /** * 只读事务 */ boolean readOnly() default false; /** * 指定哪些异常类型必须导致事务回滚,指定Throwable的子类型;默认只回滚RuntimeException和Error */ Class<? extends Throwable>[] rollbackFor() default {}; /** * 指示哪些异常类型必须导致事务回滚,这里异常类名称 */ String[] rollbackForClassName() default {}; /** * 指定哪些异常不进行回滚 */ Class<? extends Throwable>[] noRollbackFor() default {}; /** * 指定哪些异常类型不进行回滚,异常类型名称 */ String[] noRollbackForClassName() default {}; } @Transactional注解如何解析成事务属性 AnnotationTransactionAttributeSource类

从类图看我们关注AnnotationTransactionAttributeSource通过SpringTransactionAnnotationParser@Transcation转成事务属性供Spring事务处理使用。

  1. 如果@Transcation注解配置了属性,转换成RuleBasedTransactionAttribute
  2. 如果@Transcation注解没有配置属性,转换成DefaultTransactionAttribute,只有在抛出RuntimeExceptionError时候才回滚

按照Spring源码设计设计的一般套路我们看下右侧的TransactionAttributeSource 接口和抽象类AbstractFallbackTransactionAttributeSource

TransactionAttributeSource 接口

public interface TransactionAttributeSource { /**确定给定的类是否是TransactionAttributeSource元数据格式的事务属性的候选类*/ default boolean isCandidateClass(Class<?> targetClass) { return true; } /**解析给定方法的@Transaction事务属性,如果方法是非事务性的,则返回null*/ @Nullable TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass); } AbstractFallbackTransactionAttributeSource类

先看getTransactionAttribute()方法

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 判断method所在的class是不是Object类型 if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. // 构建缓存key Object cacheKey = getCacheKey(method, targetClass); // 从缓存中获取 @1 TransactionAttribute cached = this.attributeCache.get(cacheKey); // 有缓存,不会每次computeTransactionAttribute if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. // 判断缓存中的对象是不是空事务属性的对象 if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { // 存在就直接返回事务属性 return cached; } } else { // We need to work it out. // 查找我们的事务注解 TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. // 若解析出来的事务注解属性为空 if (txAttr == null) { // 往缓存中存放空事务注解属性 this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { // 我们执行方法的描述符:包名+类名+方法名 String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); // 把方法描述设置到事务属性上去 if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } // 加入缓存 this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }

缓存中有类对应方法的事务属性就直接返回,没有就先解析@1再缓存起来。

computeTransactionAttribute方法

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. // 首先判断方法是否是public,默认是支持public的 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. // method代表接口中的方法,specificMethod代表实现类中的方法 Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); // First try is the method in the target class. // 优先方法上解析的事务注解的属性,会去找父类或者接口的方法 TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // Second try is the transaction attribute on the target class. // 如果没有,再尝试声明该方法的类上注解属性,会去父类或者接口找 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } // 如果指定方法不等于方法 if (specificMethod != method) { // Fallback is to look at the original method. // 查找接口方法 txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // Last fallback is the class of the original method. // 到接口中的类中去寻找 txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null; }

查找事务属性的查找顺序如下:

  1. 特定的目标方法,会去找父类或者接口的方法
  2. 目标类,会去找父类或者接口
  3. 声明的方法
  4. 声明方法所在的类

AnnotationTransactionAttributeSource#determineTransactionAttribute() 方法委托给SpringTransactionAnnotationParser解析给定类或是方法上的@Transactional注解的事务属性

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { // 获取我们的注解解析器 for (TransactionAnnotationParser parser : this.annotationParsers) { // 通过注解解析器去解析我们的元素(方法或者类)上的注解 TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; }

接下来看下是如何解析和包装的SpringTransactionAnnotationParser#parseTransactionAnnotation()方法。

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { // 从element对象中获取@Transactional注解,然后把注解属性封装到了AnnotationAttributes AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { // 解析出真正的事务属性对象 return parseTransactionAnnotation(attributes); } else { return null; } }

分析2个点:

  • AnnotatedElementUtils.findMergedAnnotationAttributes()负责解析目标类或目标方法上的@Transactional,会向上找父类或是接口的
  • parseTransactionAnnotation()方法包装成TransactionAttribute

看下是如何包装转换的。

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { // 创建一个基础规则的事务属性对象 RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); // 解析@Transactionl上的传播行为 Propagation propagation = attributes.getEnum("propagation"); rbta.setPropagationBehavior(propagation.value()); // 解析@Transactionl上的隔离级别 Isolation isolation = attributes.getEnum("isolation"); rbta.setIsolationLevel(isolation.value()); // 解析@Transactionl上的事务超时事件 rbta.setTimeout(attributes.getNumber("timeout").intValue()); // 解析readOnly rbta.setReadOnly(attributes.getBoolean("readOnly")); // 解析@Transactionl上的事务管理器的名称 rbta.setQualifier(attributes.getString("value")); List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); // 解析针对哪种异常回滚 for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } // 对哪种异常进行回滚 for (String rbRule : attributes.getStringArray("rollbackForClassName")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } // 对哪种异常不回滚 for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } // 对哪种类型不回滚 for (String rbRule : attributes.getStringArray("noRollbackForClassName")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; }

至此,@Transactional是如何变成RuleBasedTransactionAttribute已经很清晰了。

如何自动生成代理对象

这部分和之前的声明式AOP的源码分析是一样的过程,通过类图过一下。

  1. 谁负责创建代理?

    InfrastructureAdvisorAutoProxyCreator继承我们熟悉的AbstractAdvisorAutoProxyCreator类,是个BeanPostProcessor,在Spring容器启动的过程中,会拦截bean的创建过程,为需要事务支持的bean生成代理对象。

  2. 谁负责判断bean是否需要代理?

    BeanFactoryTransactionAttributeSourceAdvisor是个Advisor,组合了切点和通知。哪些bean需要代理满足增强由切点TransactionAttributeSourcePointcut来通过TransactionAttributeSource来判定bean的类或是方法上是否有@Transactional注解。

  3. 谁负责实际的事务增强工作?

    TransactionInterceptor 继承MethodInterceptor是个拦截器,负责拦截代理对象目标方法,在前后增加事务控制的逻辑。这个类下面进行详细分析。

TransactionInterceptor 如何进行事务控制 TransactionInterceptor类

Spring中声明式事务时通过AOP的方式实现的,事务方法的执行最终都会由TransactionInterceptor invoke()拦截增强的。

package org.springframework.transaction.interceptor; public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { public Object invoke(MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. // 获取我们的代理对象的class属性 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... /** * 以事务的方式调用目标方法 * 在这埋了一个钩子函数 用来回调目标方法的 */ return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }

事务的实现是委托给TransactionAspectSupport父类实现的。

TransactionAspectSupport类 invokeWithinTransaction() 方法

基于环绕通知的实现事务控制,委托给该类上的其他几个模板方法,其实里面主要内容就是编程式的事务控制了。这是个模板方法,主要功能点如下:

  • 如何获取事务管理器对象
  • 通过事务管理器开启事务
  • 执行目标方法
  • 方法异常如何完成事务
  • 正常返回如何完成事务提交

@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // 获取我们的事务属性源对象 TransactionAttributeSource tas = getTransactionAttributeSource(); // 通过事务属性源对象获取到当前方法的事务属性信息 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // @1获取我们配置的事务管理器对象 final TransactionManager tm = determineTransactionManager(txAttr); PlatformTransactionManager ptm = asPlatformTransactionManager(tm); // 获取连接点的唯一标识 类名+方法名 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 声明式事务处理 if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // @2创建TransactionInfo TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // 执行被增强方法,调用具体的处理逻辑 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { //@3 异常回滚 如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { //清除事务信息,恢复线程私有的老的事务信息 cleanupTransactionInfo(txInfo); } //成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作 commitTransactionAfterReturning(txInfo); return retVal; } } determineTransactionManager() 事务管理器获取

查找和获取的顺序是:

  1. 先看@Transactional中是否通过value或者transactionManager指定了事务管理器
  2. TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器
  3. TransactionInterceptor.transactionManager是否有值,如果有则返回,这个是通过容器TransactionManagementConfigurer接口设置到TransactionInterceptor中的
  4. 如果上面3种都没有,将从Spring容器中查找TransactionManager类型的作为默认事务管理器

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) { // Do not attempt to lookup tx manager if no tx attributes are set // txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器 if (txAttr == null || this.beanFactory == null) { return getTransactionManager(); } //qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称 String qualifier = txAttr.getQualifier(); if (StringUtils.hasText(qualifier)) { //从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean return determineQualifiedTransactionManager(this.beanFactory, qualifier); } else if (StringUtils.hasText(this.transactionManagerBeanName)) { //从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName); } else { //最后通过类型TransactionManager在spring容器中找事务管理器 TransactionManager defaultTransactionManager = getTransactionManager(); if (defaultTransactionManager == null) { defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class); this.transactionManagerCache.putIfAbsent( DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager); } } return defaultTransactionManager; } } createTransactionIfNecessary() 创建并开启事务

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { // 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr if (txAttr != null && txAttr.getName() == null) { txAttr = new DelegatingTransactionAttribute(txAttr) { @Override public String getName() { return joinpointIdentification; } }; } TransactionStatus status = null; if (txAttr != null) { if (tm != null) { // @1获取TransactionStatus事务状态信息 status = tm.getTransaction(txAttr); } } // @2根据指定的属性与status准备一个TransactionInfo, return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }

分析如下:

  • @1获取TransactionStatus事务状态信息,也就是是编程式事务的创建和开启。
  • @2TransactionInfo生成

prepareTransactionInfo() 方法创建事务信息并绑定到当前线程

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { // 创建事务信息 TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null) { // The transaction manager will flag an error if an incompatible tx already exists. // 设置新事务状态 txInfo.newTransactionStatus(status); } // 事务信息绑定到当前线程 txInfo.bindToThread(); return txInfo; }

事务信息是有哪些内容?简单过一下内部类TransactionInfo

/** * 用于保存事务信息的不透明对象。子类必须将其传递回该类的方法,但不能看到其内部 */ protected static final class TransactionInfo { /** 事务管理器 */ @Nullable private final PlatformTransactionManager transactionManager; /** 事务属性 */ @Nullable private final TransactionAttribute transactionAttribute; /** 切点标识名 */ private final String joinpointIdentification; /** 事务状态 */ @Nullable private TransactionStatus transactionStatus; /** 旧的事务信息 */ @Nullable private TransactionInfo oldTransactionInfo; /** * 绑定新事务到当前线程,旧的会被保存 */ private void bindToThread() { this.oldTransactionInfo = transactionInfoHolder.get(); transactionInfoHolder.set(this); } /** * 恢复线程中旧事务信息 */ private void restoreThreadLocalStatus() { transactionInfoHolder.set(this.oldTransactionInfo); } } completeTransactionAfterThrowing() 异常后完成事务

/** * 如果支持回滚的话就进行回滚,否则就处理提交,提交里面如果TransactionStatus.isRollbackOnly()=true的话也会进行回滚处理 */ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } // @1判断事务是否需要回滚 if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { // 进行回滚 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } } else { // We don't roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { // @2通过事务管理器提交事务 txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } } }

异常后如果匹配上我们@Transaction指定的异常类型,在调用事务管理器进行事务回滚,否则通过事务管理器进行提交事务。

commitTransactionAfterReturning 正常完成事务

通过事务管理器进行事务提交。

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } 小结

TransactionInterceptor 对事务控制包括开启、提交、回滚等操作,其实都是通过事务管理器进行的,这和编程式事务管理是一样的。

总结

本文进行了Spring中@Transactional声明事务的源码解析,结合了声明式AOP的源码分析和编程式事务管理的源码分析。总结下过程是就是通过BeanPostProcessor拦截bean创建过程自动创建代理对象,通过TransactionInterceptor 环绕通知增强目标方法,在目标方法执行前后增加事务的控制逻辑。

知识分享,转载请注明出处。学无先后,达者为先!

本文共计4851个文字,预计阅读时间需要20分钟。

Spring系列28:如何深入解析@Transactional事务源码?

原文内容:本文内容+ @Transactional事务使用+ @EnableTransactionManagement详解+ @Transactional事务属性的解析+ TransactionInterceptor事务控制+声明式事务使用和原理声明式事务的主要步骤+ 使用@EnableTransactionManagement启用事务

改写后:本文介绍@EnableTransactionManagement的使用及事务控制原理,包括事务属性解析、TransactionInterceptor和声明式事务步骤。

本文内容
  1. @Transactional事务使用

  2. @EnableTransactionManagement 详解

  3. @Transactional事务属性的解析

  4. TransactionInterceptor 事务控制

声明式事务使用和原理 声明式的主要步骤
  1. 使用@EnableTransactionManagement启用Spring 事务管理支持
  2. 使用@Transactional标识需要事务的方法会自动开启事务
  3. 注入数据源和事务管理器

下面通过案例演示一下上面的效果。

案例
  1. 使用@EnableTransactionManagement启用Spring 事务管理支持,配置类上需要有@Configuration注解

    @Configuration @ComponentScan @EnableTransactionManagement public class AppConfig {}

  2. 使用@Transactional标识需要事务的方法会自动开启事务。addUser方法需要事务

    @Service public class UserService { @Autowired private JdbcTemplate jdbcTemplate; @Transactional public void addUser() { System.out.println("执行前记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); jdbcTemplate.update("insert into t_user (name) values (?)", "xx"); jdbcTemplate.update("insert into t_user (name) values (?)", "oo"); System.out.println("执行后记录:" + jdbcTemplate.queryForList("SELECT * from t_user")); } }

  3. 注入数据源和事务管理器

    @Configuration @ComponentScan @EnableTransactionManagement public class AppConfig { /** * 定义一个数据源 * @return */ @Bean public DataSource dataSource() { DruidDataSource dataSource = new DruidDataSource(); dataSource.setDriverClassName(""); dataSource.setDriverClassName("com.mysql.jdbc.Driver"); dataSource.setUrl("jdbc:mysql://192.168.25.24:3306/xxx?characterEncoding=UTF-8"); dataSource.setUsername("root"); dataSource.setPassword("xxx"); return dataSource; } /** * 定义一个JdbcTemplate来执行sql * @param dataSource * @return */ @Bean public JdbcTemplate jdbcTemplate(DataSource dataSource) { return new JdbcTemplate(dataSource); } /** * 定义一个管理器 * @param dataSource * @return */ @Bean public PlatformTransactionManager transactionManager(DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }

  4. 测试程序

    public class DeclarativeTest { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class); UserService userService = context.getBean(UserService.class); userService.addUser(); context.close(); } }

    输出结果如下:

    执行前记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}] 执行后记录:[{id=1, name=test1-1}, {id=2, name=test1-2}, {id=3, name=xx}, {id=4, name=oo}, {id=5, name=xx}, {id=6, name=oo}, {id=7, name=xx}, {id=8, name=oo}]

原理

@EnableTransactionManagement注解会开启Spring自动管理事务的功能。开启之后在Spring容器启动的过程中,会拦截所有bean的创建过程,判断bean 是否需要让Spring来管理事务,如果需要那么通过aop的方式创建代理对象。代理中会添加一个拦截器TransactionInterceptor,拦截@Trasaction标识方法的执行,在方法执行前后添加事务的功能。

Spring系列28:如何深入解析@Transactional事务源码?

下面进行源码分析,需要用到的前置只是是Spring Aop相关知识和编程式事务管理的知识,前面的文章有涉及,提前看一下。

@EnableTransactionManagement 详解

@EnableTransactionManagement 会开启Spring的事务管理功能,查看下源码。

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(TransactionManagementConfigurationSelector.class) public @interface EnableTransactionManagement { /** * 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)。默认为false。 * 仅当mode()设置为AdviceMode.PROXY时适用。 */ boolean proxyTargetClass() default false; /** * 指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。 * 请注意,代理模式只允许通过代理拦截调用。同一类内的本地调用不会被拦截; * 在本地调用中,对这种方法的Transactional注释将被忽略,因为Spring的拦截器甚至不会在这样的运行时场景中起作用。 */ AdviceMode mode() default AdviceMode.PROXY; /** * 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE */ int order() default Ordered.LOWEST_PRECEDENCE; } 3个参数属性值

  • proxyTargetClass : 指示是否创建基于子类(CGLIB)的代理(true),而不是标准的基于Java接口的代理(false)
  • mode:指示应该如何应用事务通知。 默认值是AdviceMode.PROXY。
  • order: 当在特定连接点上应用多个通知时,指示事务顾问程序的执行顺序。 默认值是Ordered.LOWEST_PRECEDENCE,最后处理事务拦截器。
TransactionManagementConfigurationSelector

重点是@Import(TransactionManagementConfigurationSelector.class),注入一些事务相关的bean到Spring容器中进行事务的管理控制。

根据EnableTransactionManagement的mode值选择应该使用AbstractTransactionManagementConfiguration的哪个实现。

package org.springframework.transaction.annotation; public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> { /** * 此处是AdviceMode的作用,默认是用代理,另外一个是ASPECTJ */ @Override protected String[] selectImports(AdviceMode adviceMode) { switch (adviceMode) { case PROXY: // @1 return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()}; case ASPECTJ: return new String[] {determineTransactionAspectClass()}; default: return null; } } private String determineTransactionAspectClass() { return (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader()) ? TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME : TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME); } }

我们的mode是 AdviceMode.PROXY ,所以走@1位置,注入AutoProxyRegistrarProxyTransactionManagementConfiguration

AutoProxyRegistrar注入 InfrastructureAdvisorAutoProxyCreator

AutoProxyRegistrar的作用是注入一个InfrastructureAdvisorAutoProxyCreator,用于拦截bean的创建过程,为需要的事务控制的bean 创建代理对象,这个类非常关键,后面详细讲。

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar { public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean candidateFound = false; Set<String> annTypes = importingClassMetadata.getAnnotationTypes(); // 遍历所有注解,找到有mode和proxyTargetClass的注解 for (String annType : annTypes) { AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType); if (candidate == null) { continue; } Object mode = candidate.get("mode"); Object proxyTargetClass = candidate.get("proxyTargetClass"); if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) { candidateFound = true; if (mode == AdviceMode.PROXY) { // 注册aop InfrastructureAdvisorAutoProxyCreator 不展开 AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry); // 强制设置proxyTargetClass=true后面使用cglib if ((Boolean) proxyTargetClass) { AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry); return; } } } } } } ProxyTransactionManagementConfiguration

@Configuration(proxyBeanMethods = false) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @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; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor(TransactionAttributeSource transactionAttributeSource) { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }

ProxyTransactionManagementConfiguration 代理事务配置,注册事务需要用的一些类,而且Role=ROLE_INFRASTRUCTURE都是属于内部级别的,如下:

  • BeanFactoryTransactionAttributeSourceAdvisor 事务属性通知器,存放事务注解的方法相关的属性
  • TransactionAttributeSource事务属性源,就是事务注解的一些属性,也用来解析事务注解属性,实际是AnnotationTransactionAttributeSource
  • TransactionInterceptor事务拦截器,该类包含与Spring底层事务API的集成。TransactionInterceptor简单地以正确的顺序调用相关的超类方法,比如invokeWithinTransaction。这个类非常关键,负责事务相关的AOP增强的。
小结

EnableTransactionManagement注解的作用主要注入了InfrastructureAdvisorAutoProxyCreator负责拦截bean的创建过程为特定的bean创建代理对象,并通过TransactionInterceptor事务拦截器来实现方法的事务控制。

@Transactional 详解

该注解用于描述单个方法或类上的事务属性。在类级别,该注释作为默认值应用于声明类及其子类的所有方法。注意,类级别它并不适用于类层次结构上的父类,也就是父类方法需要在本地重新声明,以便参与子类级别的注释。

注解的属性的语义的具体信息,由 TransactionDefinitionTransactionAttribute 提供。

package org.springframework.transaction.annotation; @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Transactional { @AliasFor("transactionManager") String value() default ""; /** * 用来确定目标事务管理器bean */ @AliasFor("value") String transactionManager() default ""; /** * 事务传播类型 */ Propagation propagation() default Propagation.REQUIRED; /** * 事务隔离级别 */ Isolation isolation() default Isolation.DEFAULT; /** * 事务超时 */ int timeout() default TransactionDefinition.TIMEOUT_DEFAULT; /** * 只读事务 */ boolean readOnly() default false; /** * 指定哪些异常类型必须导致事务回滚,指定Throwable的子类型;默认只回滚RuntimeException和Error */ Class<? extends Throwable>[] rollbackFor() default {}; /** * 指示哪些异常类型必须导致事务回滚,这里异常类名称 */ String[] rollbackForClassName() default {}; /** * 指定哪些异常不进行回滚 */ Class<? extends Throwable>[] noRollbackFor() default {}; /** * 指定哪些异常类型不进行回滚,异常类型名称 */ String[] noRollbackForClassName() default {}; } @Transactional注解如何解析成事务属性 AnnotationTransactionAttributeSource类

从类图看我们关注AnnotationTransactionAttributeSource通过SpringTransactionAnnotationParser@Transcation转成事务属性供Spring事务处理使用。

  1. 如果@Transcation注解配置了属性,转换成RuleBasedTransactionAttribute
  2. 如果@Transcation注解没有配置属性,转换成DefaultTransactionAttribute,只有在抛出RuntimeExceptionError时候才回滚

按照Spring源码设计设计的一般套路我们看下右侧的TransactionAttributeSource 接口和抽象类AbstractFallbackTransactionAttributeSource

TransactionAttributeSource 接口

public interface TransactionAttributeSource { /**确定给定的类是否是TransactionAttributeSource元数据格式的事务属性的候选类*/ default boolean isCandidateClass(Class<?> targetClass) { return true; } /**解析给定方法的@Transaction事务属性,如果方法是非事务性的,则返回null*/ @Nullable TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass); } AbstractFallbackTransactionAttributeSource类

先看getTransactionAttribute()方法

public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // 判断method所在的class是不是Object类型 if (method.getDeclaringClass() == Object.class) { return null; } // First, see if we have a cached value. // 构建缓存key Object cacheKey = getCacheKey(method, targetClass); // 从缓存中获取 @1 TransactionAttribute cached = this.attributeCache.get(cacheKey); // 有缓存,不会每次computeTransactionAttribute if (cached != null) { // Value will either be canonical value indicating there is no transaction attribute, // or an actual transaction attribute. // 判断缓存中的对象是不是空事务属性的对象 if (cached == NULL_TRANSACTION_ATTRIBUTE) { return null; } else { // 存在就直接返回事务属性 return cached; } } else { // We need to work it out. // 查找我们的事务注解 TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass); // Put it in the cache. // 若解析出来的事务注解属性为空 if (txAttr == null) { // 往缓存中存放空事务注解属性 this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE); } else { // 我们执行方法的描述符:包名+类名+方法名 String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass); // 把方法描述设置到事务属性上去 if (txAttr instanceof DefaultTransactionAttribute) { ((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification); } if (logger.isTraceEnabled()) { logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr); } // 加入缓存 this.attributeCache.put(cacheKey, txAttr); } return txAttr; } }

缓存中有类对应方法的事务属性就直接返回,没有就先解析@1再缓存起来。

computeTransactionAttribute方法

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) { // Don't allow no-public methods as required. // 首先判断方法是否是public,默认是支持public的 if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) { return null; } // The method may be on an interface, but we need attributes from the target class. // If the target class is null, the method will be unchanged. // method代表接口中的方法,specificMethod代表实现类中的方法 Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); // First try is the method in the target class. // 优先方法上解析的事务注解的属性,会去找父类或者接口的方法 TransactionAttribute txAttr = findTransactionAttribute(specificMethod); if (txAttr != null) { return txAttr; } // Second try is the transaction attribute on the target class. // 如果没有,再尝试声明该方法的类上注解属性,会去父类或者接口找 txAttr = findTransactionAttribute(specificMethod.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } // 如果指定方法不等于方法 if (specificMethod != method) { // Fallback is to look at the original method. // 查找接口方法 txAttr = findTransactionAttribute(method); if (txAttr != null) { return txAttr; } // Last fallback is the class of the original method. // 到接口中的类中去寻找 txAttr = findTransactionAttribute(method.getDeclaringClass()); if (txAttr != null && ClassUtils.isUserLevelMethod(method)) { return txAttr; } } return null; }

查找事务属性的查找顺序如下:

  1. 特定的目标方法,会去找父类或者接口的方法
  2. 目标类,会去找父类或者接口
  3. 声明的方法
  4. 声明方法所在的类

AnnotationTransactionAttributeSource#determineTransactionAttribute() 方法委托给SpringTransactionAnnotationParser解析给定类或是方法上的@Transactional注解的事务属性

protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) { // 获取我们的注解解析器 for (TransactionAnnotationParser parser : this.annotationParsers) { // 通过注解解析器去解析我们的元素(方法或者类)上的注解 TransactionAttribute attr = parser.parseTransactionAnnotation(element); if (attr != null) { return attr; } } return null; }

接下来看下是如何解析和包装的SpringTransactionAnnotationParser#parseTransactionAnnotation()方法。

public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) { // 从element对象中获取@Transactional注解,然后把注解属性封装到了AnnotationAttributes AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes( element, Transactional.class, false, false); if (attributes != null) { // 解析出真正的事务属性对象 return parseTransactionAnnotation(attributes); } else { return null; } }

分析2个点:

  • AnnotatedElementUtils.findMergedAnnotationAttributes()负责解析目标类或目标方法上的@Transactional,会向上找父类或是接口的
  • parseTransactionAnnotation()方法包装成TransactionAttribute

看下是如何包装转换的。

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) { // 创建一个基础规则的事务属性对象 RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute(); // 解析@Transactionl上的传播行为 Propagation propagation = attributes.getEnum("propagation"); rbta.setPropagationBehavior(propagation.value()); // 解析@Transactionl上的隔离级别 Isolation isolation = attributes.getEnum("isolation"); rbta.setIsolationLevel(isolation.value()); // 解析@Transactionl上的事务超时事件 rbta.setTimeout(attributes.getNumber("timeout").intValue()); // 解析readOnly rbta.setReadOnly(attributes.getBoolean("readOnly")); // 解析@Transactionl上的事务管理器的名称 rbta.setQualifier(attributes.getString("value")); List<RollbackRuleAttribute> rollbackRules = new ArrayList<>(); // 解析针对哪种异常回滚 for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } // 对哪种异常进行回滚 for (String rbRule : attributes.getStringArray("rollbackForClassName")) { rollbackRules.add(new RollbackRuleAttribute(rbRule)); } // 对哪种异常不回滚 for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } // 对哪种类型不回滚 for (String rbRule : attributes.getStringArray("noRollbackForClassName")) { rollbackRules.add(new NoRollbackRuleAttribute(rbRule)); } rbta.setRollbackRules(rollbackRules); return rbta; }

至此,@Transactional是如何变成RuleBasedTransactionAttribute已经很清晰了。

如何自动生成代理对象

这部分和之前的声明式AOP的源码分析是一样的过程,通过类图过一下。

  1. 谁负责创建代理?

    InfrastructureAdvisorAutoProxyCreator继承我们熟悉的AbstractAdvisorAutoProxyCreator类,是个BeanPostProcessor,在Spring容器启动的过程中,会拦截bean的创建过程,为需要事务支持的bean生成代理对象。

  2. 谁负责判断bean是否需要代理?

    BeanFactoryTransactionAttributeSourceAdvisor是个Advisor,组合了切点和通知。哪些bean需要代理满足增强由切点TransactionAttributeSourcePointcut来通过TransactionAttributeSource来判定bean的类或是方法上是否有@Transactional注解。

  3. 谁负责实际的事务增强工作?

    TransactionInterceptor 继承MethodInterceptor是个拦截器,负责拦截代理对象目标方法,在前后增加事务控制的逻辑。这个类下面进行详细分析。

TransactionInterceptor 如何进行事务控制 TransactionInterceptor类

Spring中声明式事务时通过AOP的方式实现的,事务方法的执行最终都会由TransactionInterceptor invoke()拦截增强的。

package org.springframework.transaction.interceptor; public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { public Object invoke(MethodInvocation invocation) throws Throwable { // Work out the target class: may be {@code null}. // The TransactionAttributeSource should be passed the target class // as well as the method, which may be from an interface. // 获取我们的代理对象的class属性 Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); // Adapt to TransactionAspectSupport's invokeWithinTransaction... /** * 以事务的方式调用目标方法 * 在这埋了一个钩子函数 用来回调目标方法的 */ return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed); }

事务的实现是委托给TransactionAspectSupport父类实现的。

TransactionAspectSupport类 invokeWithinTransaction() 方法

基于环绕通知的实现事务控制,委托给该类上的其他几个模板方法,其实里面主要内容就是编程式的事务控制了。这是个模板方法,主要功能点如下:

  • 如何获取事务管理器对象
  • 通过事务管理器开启事务
  • 执行目标方法
  • 方法异常如何完成事务
  • 正常返回如何完成事务提交

@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // 获取我们的事务属性源对象 TransactionAttributeSource tas = getTransactionAttributeSource(); // 通过事务属性源对象获取到当前方法的事务属性信息 final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); // @1获取我们配置的事务管理器对象 final TransactionManager tm = determineTransactionManager(txAttr); PlatformTransactionManager ptm = asPlatformTransactionManager(tm); // 获取连接点的唯一标识 类名+方法名 final String joinpointIdentification = methodIdentification(method, targetClass, txAttr); // 声明式事务处理 if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) { // @2创建TransactionInfo TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification); Object retVal; try { // 执行被增强方法,调用具体的处理逻辑 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { //@3 异常回滚 如何走?可能只需提交,也可能只需回滚,这个取决于事务的配置 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { //清除事务信息,恢复线程私有的老的事务信息 cleanupTransactionInfo(txInfo); } //成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作 commitTransactionAfterReturning(txInfo); return retVal; } } determineTransactionManager() 事务管理器获取

查找和获取的顺序是:

  1. 先看@Transactional中是否通过value或者transactionManager指定了事务管理器
  2. TransactionInterceptor.transactionManagerBeanName是否有值,如果有,将通过这个值查找事务管理器
  3. TransactionInterceptor.transactionManager是否有值,如果有则返回,这个是通过容器TransactionManagementConfigurer接口设置到TransactionInterceptor中的
  4. 如果上面3种都没有,将从Spring容器中查找TransactionManager类型的作为默认事务管理器

protected TransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) { // Do not attempt to lookup tx manager if no tx attributes are set // txAttr == null || this.beanFactory == null ,返回拦截器中配置的事务管理器 if (txAttr == null || this.beanFactory == null) { return getTransactionManager(); } //qualifier就是@Transactional注解中通过value或者transactionManager来指定事务管理器的bean名称 String qualifier = txAttr.getQualifier(); if (StringUtils.hasText(qualifier)) { //从spring容器中查找[beanName:qualifier,type:TransactionManager]的bean return determineQualifiedTransactionManager(this.beanFactory, qualifier); } else if (StringUtils.hasText(this.transactionManagerBeanName)) { //从spring容器中查找[beanName:this.transactionManagerBeanName,type:TransactionManager]的bean return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName); } else { //最后通过类型TransactionManager在spring容器中找事务管理器 TransactionManager defaultTransactionManager = getTransactionManager(); if (defaultTransactionManager == null) { defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class); this.transactionManagerCache.putIfAbsent( DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager); } } return defaultTransactionManager; } } createTransactionIfNecessary() 创建并开启事务

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) { // 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttr if (txAttr != null && txAttr.getName() == null) { txAttr = new DelegatingTransactionAttribute(txAttr) { @Override public String getName() { return joinpointIdentification; } }; } TransactionStatus status = null; if (txAttr != null) { if (tm != null) { // @1获取TransactionStatus事务状态信息 status = tm.getTransaction(txAttr); } } // @2根据指定的属性与status准备一个TransactionInfo, return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); }

分析如下:

  • @1获取TransactionStatus事务状态信息,也就是是编程式事务的创建和开启。
  • @2TransactionInfo生成

prepareTransactionInfo() 方法创建事务信息并绑定到当前线程

protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) { // 创建事务信息 TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification); if (txAttr != null) { // The transaction manager will flag an error if an incompatible tx already exists. // 设置新事务状态 txInfo.newTransactionStatus(status); } // 事务信息绑定到当前线程 txInfo.bindToThread(); return txInfo; }

事务信息是有哪些内容?简单过一下内部类TransactionInfo

/** * 用于保存事务信息的不透明对象。子类必须将其传递回该类的方法,但不能看到其内部 */ protected static final class TransactionInfo { /** 事务管理器 */ @Nullable private final PlatformTransactionManager transactionManager; /** 事务属性 */ @Nullable private final TransactionAttribute transactionAttribute; /** 切点标识名 */ private final String joinpointIdentification; /** 事务状态 */ @Nullable private TransactionStatus transactionStatus; /** 旧的事务信息 */ @Nullable private TransactionInfo oldTransactionInfo; /** * 绑定新事务到当前线程,旧的会被保存 */ private void bindToThread() { this.oldTransactionInfo = transactionInfoHolder.get(); transactionInfoHolder.set(this); } /** * 恢复线程中旧事务信息 */ private void restoreThreadLocalStatus() { transactionInfoHolder.set(this.oldTransactionInfo); } } completeTransactionAfterThrowing() 异常后完成事务

/** * 如果支持回滚的话就进行回滚,否则就处理提交,提交里面如果TransactionStatus.isRollbackOnly()=true的话也会进行回滚处理 */ protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) { if (txInfo != null && txInfo.getTransactionStatus() != null) { if (logger.isTraceEnabled()) { logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex); } // @1判断事务是否需要回滚 if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) { try { // 进行回滚 txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus()); } } else { // We don't roll back on this exception. // Will still roll back if TransactionStatus.isRollbackOnly() is true. try { // @2通过事务管理器提交事务 txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } } }

异常后如果匹配上我们@Transaction指定的异常类型,在调用事务管理器进行事务回滚,否则通过事务管理器进行提交事务。

commitTransactionAfterReturning 正常完成事务

通过事务管理器进行事务提交。

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) { if (txInfo != null && txInfo.getTransactionStatus() != null) { txInfo.getTransactionManager().commit(txInfo.getTransactionStatus()); } } 小结

TransactionInterceptor 对事务控制包括开启、提交、回滚等操作,其实都是通过事务管理器进行的,这和编程式事务管理是一样的。

总结

本文进行了Spring中@Transactional声明事务的源码解析,结合了声明式AOP的源码分析和编程式事务管理的源码分析。总结下过程是就是通过BeanPostProcessor拦截bean创建过程自动创建代理对象,通过TransactionInterceptor 环绕通知增强目标方法,在目标方法执行前后增加事务的控制逻辑。

知识分享,转载请注明出处。学无先后,达者为先!