Spring和事务的集成与原理实现

目录

一、Spring代码示例

1.pom.xml文件相关配置

2.application.xml文件配置

二、Spring集成原理分析

1.Spring事务与AOP的集成

1.1 Spring事务和AOP集成流程

1.2 TransactionInterceptor类

1.3 AOP切入点Pointcut接口

2.Spring事务原理执行流程

2.1 DataSourceTransactionManager类

2.2 PlatformTransactionManager接口

2.3 invokeWithinTransaction方法

2.4 createTransactionIfNecessary方法

2.5 completeTransactionAfterThrowing方法

2.6 commitTransactionAfterReturning方法

三、Springboot和事务的自动集成

1.DataSourceTransactionManagerAutoConfiguration类

2.TransactionAutoConfiguration类

3.EnableTransactionManagement注解

4.TransactionManagementConfigurationSelector类

5.AutoProxyRegistrar类

6.ProxyTransactionManagementConfiguration类

7.AnnotationTransactionAttributeSource类

8.SpringTransactionAnnotationParser类


一、Spring代码示例

注:进行该代码示例之前必须已经集成持久化框架,可以进行数据库操作

1.pom.xml文件相关配置

配置如下:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${spring.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${spring.version}</version>
</dependency>

2.application.xml文件配置

配置如下:

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>

<!-- 拦截器方式配置事务 -->
<tx:advice id="transactionAdvisor" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="insert*"/>
        <tx:method name="delete*"/>
        <tx:method name="update*"/>
        <!-- 可以有可以没有 -->
        <tx:method name="get*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="find*" propagation="SUPPORTS" read-only="true" />
        <tx:method name="select*" propagation="SUPPORTS" read-only="true" />
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="transactionPointCut" expression="execution(* com.iboxpay.mapper.*.*(..))"/>
    <aop:advisor advice-ref="transactionAdvisor" pointcut-ref="transactionPointCut"/>
</aop:config>

根据xml文件的配置可以大致看出来spring事务是基于Aop实现的,而关于Aop的原理实现可以看到文章Spring和AOP的集成与原理实现,这里面大致描述了Aop的实现过程与原理。

二、Spring集成原理分析

1.Spring事务与AOP的集成

1.1 Spring事务和AOP集成流程

流程图如下:

其流程如下:

  1. Spring工厂调用getBean方法初始化Bean,进入到BeanPostProcessor实现类中;
  2. 在XXXXAutoProxyCreator类中从Spring工厂中获取Advisor,对于传统的XML配置来说advice是在XML中配置到Spring工厂中的,如代码实例中的一样;而对于@Trasactional注解而言具体类型是BeanFactoryTransactionAttributeSourceAdvisor,这个将在Springboot自动配置类配置进去;
  3. 使用Advisor对象中内嵌的advisorFactory对象工厂获取具体的Advice,同时将Pointcut对象也当成参数传进去,从而获取Advice以及绑定其关系。

1.2 TransactionInterceptor类

我们先看到上面配置的<tx:advice/>标签里面的配置内容,advice配置的类源码如下:

@SuppressWarnings("serial")
public class TransactionInterceptor extends TransactionAspectSupport 
        implements MethodInterceptor, Serializable {
   public TransactionInterceptor() {
   }
   public TransactionInterceptor(PlatformTransactionManager ptm, 
           Properties attributes) {
      setTransactionManager(ptm);
      setTransactionAttributes(attributes);
   }
   public TransactionInterceptor(PlatformTransactionManager ptm, 
           TransactionAttributeSource tas) {
      setTransactionManager(ptm);
      setTransactionAttributeSource(tas);
   }
   @Override
   public Object invoke(final MethodInvocation invocation) 
           throws Throwable {
      Class<?> targetClass = (invocation.getThis() != null ? 
              AopUtils.getTargetClass(invocation.getThis()) : null);
      // 调用Spring事务关键方法,InvocationCallback只是简单的调用原来的方法
      return invokeWithinTransaction(invocation.getMethod(), 
              targetClass, new InvocationCallback() {
         @Override
         public Object proceedWithInvocation() throws Throwable {
            return invocation.proceed();
         }
      });
   }
   ...
}

可以看到这个类非常简单,标明了可以序列化,并且自己实现了readObject和writeObject两个方法,同时它也实现了MethodInterceptor接口,这个接口是spring-aop中的接口,实现了这个接口代表这个类支持以AOP模式把这个类作为其它类的代理对象来进行增强操作。

接下来看到其中的invoke方法,这个方法在调用被代理类的时候将会被调用,其中会调用父类的方法invokeWithinTransaction,这个方法是实现事务过程逻辑的地方,该方法在调用时再具体分析。

而<tx:attributes/>标签则是为不同的方法提供propagation、read-only等属性。

1.3 AOP切入点Pointcut接口

在xml文件中可以看到<aop:config/>标签,这个标签中有<aop:pointcut/>和<aop:advisor/>标签,看到这两个标签估计十分熟悉,因为这两个标签对应AOP的@Pointcut注解和ADVISOR类,标明了对于advice-ref属性引用的advisor的切入点是什么。

经过上面的配置spring事务和AOP已经集成,在AbstractAutoProxyCreator类wrapIfNecessary方法中会调用getAdvicesAndAdvisorsForBean方法,该方法将会调用canApply对Pointcut进行识别,判断哪些类将会被AOP进行代理织入,实现事务的增加功能。符合条件的将会被TransactionInterceptor类进行cglib代理,在调用被代理类的方法时将会调用该类的invoke方法。

2.Spring事务原理执行流程

我们暂时定义一个操作数据库的方法"getDto",后续用getDto代表数据库操作。

走这里我们已经知道getDto数据库操作方法如何被Spring事务代理加强的,接下来跟着源码详细看下Spring事务执行流程。

2.1 DataSourceTransactionManager类

该类是Spring进行数据源事务管理通常使用的事务管理器,源码如下:

public class DataSourceTransactionManager 
        extends AbstractPlatformTransactionManager
        implements ResourceTransactionManager, InitializingBean {
   private DataSource dataSource;
   @Override
   protected Object doGetTransaction() {
      ...
   }
   @Override
   protected void doBegin(Object transaction, 
           TransactionDefinition definition) {
      ...
   }
   @Override
   protected Object doSuspend(Object transaction) {
      ...
   }
   @Override
   protected void doResume(Object transaction, Object suspendedResources) {
      ...
   }
   @Override
   protected void doCommit(DefaultTransactionStatus status) {
      ...      " transaction", ex);
      }
   }
   @Override
   protected void doRollback(DefaultTransactionStatus status) {
      ...
   }
   @Override
   protected void doSetRollbackOnly(DefaultTransactionStatus status) {
      ...
   }
}

该类的几个方法主要作用如下:

  • doBegin(Object, TransactionDefinition):开启一个新的事务,并且事务的定义将会被包含在TransactionDefinition对象中,在调用该方法前没有其它的事务存在,或者说前面的事务已经被暂停;
  • doCleanupAfterCompletion(Object):事务完成后清理事务资源;
  • doCommit(DefaultTransactionStatus):执行给定事务的提交,在该方法中只是单纯的做一个事务的提交,检查是否是新事务在此前已经被处理;
  • doGetTransaction():返回当前事务状态的事务对象,该方法的返回对象将会携带正确的事务状态和其它所有存在的事务信息,该方法被调用的地方也应该是在doBegin或者doCommit这些方法中;
  • doResume(Object, Object):恢复当前事务的资源,随后将恢复事务同步;
  • doRollback(DefaultTransactionStatus):执行给定事务的实际回滚,和commit一样,只需要执行回滚操作即可,无需进行其它的操作;
  • doSetRollbackOnly(DefaultTransactionStatus):只回滚给定事务,只有当如果当前事务参与已存在事务才会被调用;
  • doSuspend(Object):有回复事务资源,就有对应的挂起操作,该方法便是挂起当前事务的资源,调用该方法后事务同步将被挂起。

以上方法是事务执行过程将会被用到的几个,还有其它的事务执行流程便不详细分析。

2.2 PlatformTransactionManager接口

接口源码如下:

public interface PlatformTransactionManager {
   TransactionStatus getTransaction(TransactionDefinition definition) 
           throws TransactionException;
   void commit(TransactionStatus status) throws TransactionException;
   void rollback(TransactionStatus status) throws TransactionException;
}

接口的三个方法大致作用:

  • TransactionStatus getTransaction(TransactionDefinition):返回当前事务或创建一个新的事务;
  • void commit(TransactionStatus):提交给定事务,并记录其状态,需要注意的是如果该方法被调用,无论执行方法正常或抛出了异常,事务都会被标记成已完成并且清除事务资源,这种情况下不应该使用回滚;另外该方法还有额外三个作用:
    • 如果这个事务以编程方式被标记成rollback-only则执行回滚;
    • 如果事务不是新事务,则忽略提交以确保周围的事务正确参与;
    • 如果前面的事务被挂起来以创建了一个新的,在新事务提交之后恢复原来的事务;
  • void rollback(TransactionStatus):回滚给定的事务,如果事务提交异常不要尝试回滚事务当提交后事务将会被清除,即使抛出了异常,因此调用回滚将会再次抛出异常,该方法还有额外两个作用:
    • 如果事务不是新事务则设置其为rollback-only,以确保上下事务的正确执行;
    • 如果前面的事务被挂起来以创建了一个新的,在新事务回滚后将会恢复原来事务;

2.3 invokeWithinTransaction方法

接下来我们继续看到该方法来,这个方法是Spring事务执行流程的初始入口,其源码如下:

public abstract class TransactionAspectSupport 
        implements BeanFactoryAware, InitializingBean {
    protected Object invokeWithinTransaction(Method method, 
            Class<?> targetClass, final InvocationCallback invocation)
            throws Throwable {
       // 进入方法,method是getDto的封装类,targetClass为代理类
       // invocation执行的操作是调用getDto方法
       // 获取<tx:attributes/>标签的参数属性
       final TransactionAttribute txAttr = 
               getTransactionAttributeSource()
               .getTransactionAttribute(method, targetClass);
       // 获取transcationManager对象
       final PlatformTransactionManager tm = 
               determineTransactionManager(txAttr);
       // 获取被代理方法的唯一标识
       final String joinpointIdentification = 
               methodIdentification(method, targetClass, txAttr);
       // 如果txAttr为空,则方法为非事务性的,但一般的方法执行到这里txAttr不会为空
       if (txAttr == null || 
           !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
          // 创建事务信息,同时在该方法中也会同时开启事务,记录事务开启状态
          // 该方法具体的执行流程放到后续分析
          TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr,
                  joinpointIdentification);
          Object retVal = null;
          try {
             // 从进入方法invokeWithinTransaction之前可以知道这个实际上是调用了
             // getDto数据库操作方法,当然,getDto也有可能是被代理的方法
             // 例如和mybatis集成getDto方法传入进来的就是MapperFactoryBean中
             // 创建的MapperProxy代理对象代理的,也有可能是多个代理链
             retVal = invocation.proceedWithInvocation();
          }
          catch (Throwable ex) {
             // 如果执行getDto失败,在该方法中队进行事物的回滚操作,详细流程后续分析
             completeTransactionAfterThrowing(txInfo, ex);
             throw ex;
          }
          finally {
             // 清除当前事务信息,内部会清除txInfo中的ThreadLocal信息
             cleanupTransactionInfo(txInfo);
          }
          // 根据completeTransactionAfterThrowing方法执行的结果来判断最终
          // 是否提交或者直接进行回滚
          commitTransactionAfterReturning(txInfo);
          // 返回getDto结果
          return retVal;
       }
       else {
          // 此处尚且不知道有何用处,当前只能暂且猜测此流程应该是异步事务
          ...
       }
    }
}

该方法是Spring事务的入口,方法的执行流程已注释,接下来看看该方法调用的一些其它方法。

2.4 createTransactionIfNecessary方法

方法源码如下:

public abstract class TransactionAspectSupport 
        implements BeanFactoryAware, InitializingBean {
    protected TransactionInfo createTransactionIfNecessary(
            PlatformTransactionManager tm, 
            TransactionAttribute txAttr, 
            final String joinpointIdentification) {
       // 如果txAttr不为空且其中的name属性为空,则将joinpointIdentification
       // 参数作为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) {
             // 调用前面提到的getTransaction,获取一个新事务,在该方法中会调用
             // doBegin方法,以开启事务
             status = tm.getTransaction(txAttr);
          }
          else {
              // 如果没有事务管理器则打印debug日志说明没有事务管理器
          }
       }
       return prepareTransactionInfo(tm, txAttr, joinpointIdentification, 
               status);
    }
    protected TransactionInfo prepareTransactionInfo(
            PlatformTransactionManager tm,
            TransactionAttribute txAttr, 
            String joinpointIdentification, TransactionStatus status) {
       // 根据tm、txAttr和joinpointIdentification创建事务信息
       TransactionInfo txInfo = new TransactionInfo(tm, txAttr, 
               joinpointIdentification);
       if (txAttr != null) {

          // 如果已经存在不兼容的tx,事务管理器将标记错误。
          txInfo.newTransactionStatus(status);
       }
       else {
          // 打印日志表明无需创建新的txAttr
       }
       // 将txInfo绑定到ThreadLocal中
       txInfo.bindToThread();
       return txInfo;
    }
}

调用createTransactionIfNecessary方法创建TransactionInfo事务信息,其中包含了事务状态TransactionStatus、调用方法唯一标识joinpointIdentification,事务属性TransactionAttribute、事务管理器PlatformTransactionManager以及上一个事务oldTransactionInfo属性。

2.5 completeTransactionAfterThrowing方法

方法源码如下:

public abstract class TransactionAspectSupport 
        implements BeanFactoryAware, InitializingBean {
    protected void completeTransactionAfterThrowing(TransactionInfo txInfo,
            Throwable ex) {
       // 判断txInfo是否为空且其中事务不为空
       if (txInfo != null && txInfo.hasTransaction()) {
          // 先判断哪些异常将会被回滚,一般而言是Error和运行异常RuntimeException
          // 这里需要注意的是rollbackOn这个方法将会获取noRollbackFor和
          // rollbackFor相关的四个参数,并判断ex是否是那四个参数其中某一个的子类
          // 如果是子类将会返回true
          if (txInfo.transactionAttribute.rollbackOn(ex)) {
             try {
                // 调用transactionManager的rollback回滚方法
                // 在该方法中将会调用doRollback和doSetRollbackOnly方法
                txInfo.getTransactionManager().rollback(txInfo
                        .getTransactionStatus());
             }
             // 该异常一般是IllegalTransactionStateException
             // 事务已经完成再执行回滚将会抛此异常
             catch (TransactionSystemException ex2) {
                logger.error("Application exception overridden by" +
                        " rollback exception", ex);
                ex2.initApplicationException(ex);
                throw ex2;
             }
             catch (RuntimeException ex2) {
                logger.error("Application exception overridden by" +
                        " rollback exception", ex);
                throw ex2;
             }
             catch (Error err) {
                logger.error("Application exception overridden by" +
                        " rollback error", ex);
                throw err;
             }
          }
          else {
             try {
                // 如果前面的异常回滚不支持则直接提交
                // 调用transactionManager的commit提交事务
                // 如果rollbackOnly标识为true或者其它情况将会processRollback
                // 否则processCommit
                txInfo.getTransactionManager().commit(txInfo
                        .getTransactionStatus());
             }
             // 该异常一般是IllegalTransactionStateException
             // 事务已经完成再执行提交将会抛此异常
             catch (TransactionSystemException ex2) {
                logger.error("Application exception overridden by commit" +
                        " exception", ex);
                ex2.initApplicationException(ex);
                throw ex2;
             }
             catch (RuntimeException ex2) {
                logger.error("Application exception overridden by commit" +
                        " exception", ex);
                throw ex2;
             }
             catch (Error err) {
                logger.error("Application exception overridden by commit" +
                        " error", ex);
                throw err;
             }
          }
       }
    }
}

2.6 commitTransactionAfterReturning方法

方法源码如下:

public abstract class TransactionAspectSupport 
        implements BeanFactoryAware, InitializingBean {
    protected void commitTransactionAfterReturning(TransactionInfo txInfo) {
       if (txInfo != null && txInfo.hasTransaction()) {
          txInfo.getTransactionManager()
                  .commit(txInfo.getTransactionStatus());
       }
    }
}

可以看到该方法十分简单,因为调用该方法的前提便是执行getDto方法获得了数据,意味着数据库操作方法执行成功,因此只需要获得transactionManager提交事务即可。

三、Springboot和事务的自动集成

既然谈到springboot的自动集成,那么自然跳不过一个文件:/META-INF/spring.factories,在该文件中有个配置如下:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

1.DataSourceTransactionManagerAutoConfiguration类

该类源码如下:

@Configuration
@ConditionalOnClass({ JdbcTemplate.class, 
        PlatformTransactionManager.class })
@AutoConfigureOrder(Ordered.LOWEST_PRECEDENCE)
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceTransactionManagerAutoConfiguration {
   @Configuration
   @ConditionalOnSingleCandidate(DataSource.class)
   static class DataSourceTransactionManagerConfiguration {
      private final DataSource dataSource;
      private final TransactionManagerCustomizers 
              transactionManagerCustomizers;
      DataSourceTransactionManagerConfiguration(DataSource dataSource,
            ObjectProvider<TransactionManagerCustomizers> 
                transactionManagerCustomizers) {
         this.dataSource = dataSource;
         this.transactionManagerCustomizers = 
                 transactionManagerCustomizers.getIfAvailable();
      }
      @Bean
      @ConditionalOnMissingBean(PlatformTransactionManager.class)
      public DataSourceTransactionManager 
              transactionManager(DataSourceProperties properties) {
         DataSourceTransactionManager transactionManager = 
                 new DataSourceTransactionManager(this.dataSource);
         if (this.transactionManagerCustomizers != null) {
            this.transactionManagerCustomizers
                    .customize(transactionManager);
         }
         return transactionManager;
      }
   }
}

该类的作用便是使用DataSourceProperties中的属性来创建DataSourceTransactionManager事务管理器,并且如果transactionManagerCustomizers不为空还可以对事务管理器进行一些额外的自定义处理。

2.TransactionAutoConfiguration类

TransactionAutoConfiguration类源码:

@Configuration
@ConditionalOnClass(PlatformTransactionManager.class)
@AutoConfigureAfter({ JtaAutoConfiguration.class, 
        HibernateJpaAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class, 
        Neo4jDataAutoConfiguration.class })
@EnableConfigurationProperties(TransactionProperties.class)
public class TransactionAutoConfiguration {
   @Bean
   @ConditionalOnMissingBean
   public TransactionManagerCustomizers 
           platformTransactionManagerCustomizers(
               ObjectProvider<PlatformTransactionManagerCustomizer<?>> 
                   customizers) {
      return new TransactionManagerCustomizers(customizers.orderedStream()
              .collect(Collectors.toList()));
   }
   @Configuration
   @ConditionalOnSingleCandidate(PlatformTransactionManager.class)
   public static class TransactionTemplateConfiguration {
      private final PlatformTransactionManager transactionManager;
      public TransactionTemplateConfiguration(PlatformTransactionManager 
              transactionManager) {
         this.transactionManager = transactionManager;
      }
      @Bean
      @ConditionalOnMissingBean
      public TransactionTemplate transactionTemplate() {
         return new TransactionTemplate(this.transactionManager);
      }
   }
   @Configuration
   @ConditionalOnBean(PlatformTransactionManager.class)
   @ConditionalOnMissingBean(AbstractTransactionManagementConfiguration
           .class)
   public static class EnableTransactionManagementConfiguration {
      @Configuration
      @EnableTransactionManagement(proxyTargetClass = false)
      @ConditionalOnProperty(prefix = "spring.aop", 
              name = "proxy-target-class", havingValue = "false",
              matchIfMissing = false)
      public static class JdkDynamicAutoProxyConfiguration {
      }
      @Configuration
      @EnableTransactionManagement(proxyTargetClass = true)
      @ConditionalOnProperty(prefix = "spring.aop", 
              name = "proxy-target-class", havingValue = "true",
              matchIfMissing = true)
      public static class CglibAutoProxyConfiguration {

      }
   }
}

该类的几个条件注解如下:

  • ConditionalOnClass确定PlatformTransactionManager需要在项目包中;
  • AutoConfigureAfter注解表明DataSourceTransactionManagerAutoConfiguration类已经执行完毕;
  • EnableConfigurationProperties表明TransactionProperties事务相关属性已经配置;

这三个条件确定了事务管理器的存在以及事务属性的存在,接着我们看到其中的内部类EnableTransactionManagementConfiguration上面的注解的作用:

  • ConditionalOnBean确保PlatformTransactionManager已经被创建在spring工厂中;
  • ConditionalOnMissingBean注解确保spring工厂中不含有与其类似的配置对象;

接着我们看到其中的CglibAutoProxyConfiguration类注解配置:

  • EnableTransactionManagement:该注解的作用便是实现像spring手动配置tx:advisor和attr这些属性的自动配置事务;
  • ConditionalOnProperty注解确保属性spring.aop.proxy-target-class为true才执行,而实际上springboot的该属性如果不配置默认就是true,因此绝对满足;

3.EnableTransactionManagement注解

接下来看到这个注解,注解源码如下:

@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 Ordered.LOWEST_PRECEDENCE;
}

可以看到这个注解很简单,其中最重要的便是TransactionManagementConfigurationSelector类,这个类被@Import注解引用。

4.TransactionManagementConfigurationSelector类

该类的源码如下:

public class TransactionManagementConfigurationSelector 
        extends AdviceModeImportSelector<EnableTransactionManagement> {
   @Override
   protected String[] selectImports(AdviceMode adviceMode) {
      switch (adviceMode) {
         case PROXY:
            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);
   }
}

可以看到这个类实际上是个ImportSelector,因此selectImports方法会被调用,在该方法中会判断adviceMode,而从前面的源码中可以看到默认配置是PROXY,因此会返回AutoProxyRegistrar和ProxyTransactionManagementConfiguration类。

5.AutoProxyRegistrar类

该类的源码如下:

public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
   private final Log logger = LogFactory.getLog(getClass());
   @Override
   public void registerBeanDefinitions(AnnotationMetadata 
           importingClassMetadata, BeanDefinitionRegistry registry) {
      boolean candidateFound = false;
      Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
      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) {
               AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
               if ((Boolean) proxyTargetClass) {
                  AopConfigUtils
                          .forceAutoProxyCreatorToUseClassProxying(registry);
                  return;
               }
            }
         }
      }
      if (!candidateFound && logger.isInfoEnabled()) {
         String name = getClass().getSimpleName();
      }
   }
}

可能第一眼看到这个方法比较懵逼,但是当看到registerAutoProxyCreatorIfNecessary这里面只后一切困惑迎刃而解,这个类的作用便是注册一个ADVISOR,类似Spring在xml中配置<tx:advisor/>标签的功能一样,创建一个advisor。

6.ProxyTransactionManagementConfiguration类

该类的源码如下:

@Configuration
public class ProxyTransactionManagementConfiguration 
        extends AbstractTransactionManagementConfiguration {
   @Bean(name = TransactionManagementConfigUtils
           .TRANSACTION_ADVISOR_BEAN_NAME)
   @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
   public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
      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() {
      TransactionInterceptor interceptor = new TransactionInterceptor();
      interceptor.setTransactionAttributeSource(transactionAttributeSource());
      if (this.txManager != null) {
         interceptor.setTransactionManager(this.txManager);
      }
      return interceptor;
   }
}

在这个配置类里面我们看到了熟悉的朋友TransactionInterceptor和TransactionAttributeSource两个类,对应Spring在xml文件中配置的<tx:attributes/>标签和<tx:advisor>标签。而另外一个类BeanFactoryTransactionAttributeSourceAdvisor便对应了<aop:config/>、<aop:pointcut>、<aop:advisor>那一些列标签所完成的功能。

7.AnnotationTransactionAttributeSource类

看到这里可能会有点疑惑,spring在xml文件中配置了<tx:method/>标签以及<tx:pointcut/>标签来确定哪些方法会被代理哪些不会,而看到现在都没有这个配置相关的身影。其实springboot已经将这两个配置改成了@Transactional注解配置了,接下来我们就来看看其内部的实现逻辑。

先看看类实例化相关源码:

public class AnnotationTransactionAttributeSource 
        extends AbstractFallbackTransactionAttributeSource
        implements Serializable {
    public AnnotationTransactionAttributeSource() {
       this(true);
    }
    public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
       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());
       }
    }
    @Override
    @Nullable
    protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
       return determineTransactionAttribute(clazz);
    }
    @Override
    @Nullable
    protected TransactionAttribute findTransactionAttribute(Method method) {
       return determineTransactionAttribute(method);
    }
    @Nullable
    protected TransactionAttribute determineTransactionAttribute(
            AnnotatedElement element) {
       for (TransactionAnnotationParser annotationParser : 
               this.annotationParsers) {
          TransactionAttribute attr = annotationParser
                  .parseTransactionAnnotation(element);
          if (attr != null) {
             return attr;
          }
       }
       return null;
    }
}

可以看到无论如何,都会加载SpringTransactionAnnotationParser这个类到annotationParsers属性中,而该属性会在调用findTransactionAttribute方法时依次遍历执行parseTransactionAnnotation方法,因此可以暂时断定,原来的切入点等配置具体哪个类需要代理大概率被转移到了这个类中。

8.SpringTransactionAnnotationParser类

类源码如下:

public class SpringTransactionAnnotationParser 
        implements TransactionAnnotationParser, Serializable {
    @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;
       }
    }
    protected TransactionAttribute parseTransactionAnnotation(
            AnnotationAttributes attributes) {
       RuleBasedTransactionAttribute rbta = 
               new RuleBasedTransactionAttribute();
       Propagation propagation = attributes.getEnum("propagation");
       rbta.setPropagationBehavior(propagation.value());
       Isolation isolation = attributes.getEnum("isolation");
       rbta.setIsolationLevel(isolation.value());
       rbta.setTimeout(attributes.getNumber("timeout").intValue());
       rbta.setReadOnly(attributes.getBoolean("readOnly"));
       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;
    }
}

终于看到了老朋友TransactionAttribute类和@Transaction注解了,这个类会对传进来的@Trasaction注解propagation以及readOnly等属性进行读取并使用RuleBasedTransactionAttribute对象封装起来返回,而在Springboot的TransactionInterceptor类中的invokeWithinTransaction方法会调用getTransactionAttribute方法,传入被代理方法,这样便可以在调用该方法时读取该方法的事务属性以达到<tx:method/>标签的作用了。

那么读取@Transactional注解的地方已经知道了,但是目前我们还不知道<aop:pointcut/>标签配置的地方啊,此时就又要回到BeanFactoryTransactionAttributeSourceAdvisor类中来了,这个类共有TransactionAttributeSourcePointcut和TransactionAttributeSource属性。回到以前AOP流程中来,在AOP执行流程的时候判断如果类是PointcutAdvisor则会调用canApply方法。

方法执行流程源码如下:

public static boolean canApply(Pointcut pc, Class<?> targetClass, 
        boolean hasIntroductions) {
   // 调用进来,pc则是BeanFactoryTransactionAttributeSourceAdvisor类
   // targetClass是TestSerivce(其中有个方法被@Transactional注解了)
   Assert.notNull(pc, "Pointcut must not be null");
   if (!pc.getClassFilter().matches(targetClass)) {
      return false;
   }
   // BeanFactoryTransactionAttributeSourceAdvisor继承自
   // StaticMethodMatcherPointcut类,因此methodMatcher便可以看做该类
   MethodMatcher methodMatcher = pc.getMethodMatcher();
   if (methodMatcher == MethodMatcher.TRUE) {
      
      return true;
   }
   IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
   if (methodMatcher instanceof IntroductionAwareMethodMatcher) {
      introductionAwareMethodMatcher = 
              (IntroductionAwareMethodMatcher) methodMatcher;
   }
   Set<Class<?>> classes = new LinkedHashSet<>();
   // 该方法判断类是否是代理类,如果不是则添加进classes集合中
   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) {
         // 对每个方法进行遍历,一般而言introductionAwareMethodMatcher对象
         // 为空,因此会进入到methodMatcher对象的判断中来,而在该类指的则是
         // BeanFactoryTransactionAttributeSourceAdvisor,这个类的matches
         // 方法最终会调用到getTransactionAttribute方法,该方法会对被代理方法
         // 的@Transactional注解进行读取,不为空则返回true,因此TestService
         // 类最终将会被TransactionInterceptor类所代理加强,最后调用getDto方法
         // 时将会进入该类的invoke方法,进入事务管理流程。
         if (introductionAwareMethodMatcher != null ?
               introductionAwareMethodMatcher.matches(method, targetClass,
                       hasIntroductions) :
               methodMatcher.matches(method, targetClass)) {
            return true;
         }
      }
   }
   return false;
}

关于方法执行的仔细流程已经注释,而对于methodMatcher.matches调用的方法为什么会调用进TransactionAttributeSource.getTransactionAttribute方法看下TransactionAttributeSourcePointcut类和BeanFactoryTransactionAttributeSourceAdvisor类即可。

至此,关于Springboot集成事务管理的大致流程原理便分析完毕。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值