Spring事務管理(二)-TransactionProxyFactoryBean原理

一般Spring事務管理的配置都是XML或者聲明式註解的方式,而後想要學習其運行的原理,從TransactionProxyFactoryBean深刻更合適。咱們從事務相關的核心類開始,逐步介紹Spring事務的運行機制。java

Spring事務核心類

Spring事務的構成,基本有三個部分,事務屬性的定義,事務對象及狀態信息的持有,事務管理器的處理。spring

事務屬性的定義

  1. TransactionDefinition 事務定義(傳播屬性,隔離屬性,timeout等)
  2. TransactionAttribute 事務屬性接口 (繼承TransactionDefinition),經常使用的實現是RuleBasedTransactionAttribute
  3. TransactionAttributeSource 事務屬性數據源,能夠根據method和Class獲取TransactionAttribute(註解方式的實現爲AnnotationTransactionAttributeSource,編程方式的實現爲NameMatchTransactionAttributeSource)

事務對象及狀態信息的持有

  1. Transaction 事務對象,由具體的事務管理器實現返回
  2. TransactionStatus 事務狀態,持有事務對象以及事務自己的屬性及狀態,每次事務方法執行前,生成一個新的TransactionStatus,但若是不須要建立新事務,則持有的事務和上層一致
  3. TransactionInfo 事務信息,持有事務屬性,事務狀態,事務鏈接點(方法路徑),事務管理器,每次事務方法執行,生成新的TransactionInfo,而且綁定到當前線程(ThreadLocal),同時持有上一事務信息對象,造成鏈式結構。

事務管理器的處理

  1. PlatformTransactionManager事務管理接口,AbstractPlatformTransactionManager爲其抽象實現(實現了getTransaction,commit,rollback模板方法),經常使用的實現如JDBC的事務管理實現DataSourceTransactionManager

TransactionProxyFactoryBean

TransactionProxyFactoryBean實現了FactoryBean和InitializingBean接口,FactoryBean支持對須要事務支持的類的代理,InitializingBean初始化事務環境的準備工做,完成代理對象的建立。咱們再來看下xml的配置:編程

<!-- userManager事務代理類 -->
<bean id="userManagerTransactionProxy"
   class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <!-- 原始對象 -->
   <property name="target" ref="userManager"/>
   <!-- 事務屬性 -->
   <property name="transactionAttributes">
      <props>
         <prop key="batchOperator">PROPAGATION_REQUIRED,readOnly</prop>
      </props>
   </property>
   <!-- 事務管理器 -->
   <property name="transactionManager">
      <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
         <property name="dataSource" ref="dataSource"/>
      </bean>
   </property>
</bean>

須要配置的有三個,原始對象,事務屬性和事務管理器。其中原始對象用來生成代理對象,而事務屬性和事務管理器都設置到一個很重要的對象中,即TransactionInterceptor,事務攔截器,對應AOP中的加強類,完成事務管理和方法自己的結合。app

回到TransactionProxyFactoryBean的構造,其主要實現定義在抽象父類AbstractSingletonProxyFactoryBean中。在初始化方法afterPropertiesSet中,使用最原始的ProxyFactory, 完成了代理對象的建立。ide

AbstractSingletonProxyFactoryBean.java

public void afterPropertiesSet() {
   if (this.target == null) {
      throw new IllegalArgumentException("Property 'target' is required");
   }
   if (this.target instanceof String) {
      throw new IllegalArgumentException("'target' needs to be a bean reference, not a bean name as value");
   }
   if (this.proxyClassLoader == null) {
      this.proxyClassLoader = ClassUtils.getDefaultClassLoader();
   }

   // 建立AOP代理工廠
   ProxyFactory proxyFactory = new ProxyFactory();

   // 添加前置加強攔截器
   if (this.preInterceptors != null) {
      for (Object interceptor : this.preInterceptors) {
         proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
      }
   }

   // 核心加強攔截器,有子類實現,在TransactionProxyFactoryBean中便是TransactionInterceptor
   // Add the main interceptor (typically an Advisor).
   proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(createMainInterceptor()));

   // 添加後置加強攔截器
   if (this.postInterceptors != null) {
      for (Object interceptor : this.postInterceptors) {
         proxyFactory.addAdvisor(this.advisorAdapterRegistry.wrap(interceptor));
      }
   }

   // 拷貝AOP的基本配置,如exposeProxy等
   proxyFactory.copyFrom(this);

   // 設置原始對象
   TargetSource targetSource = createTargetSource(this.target);
   proxyFactory.setTargetSource(targetSource);

   // 設置原始對象實現的接口
   if (this.proxyInterfaces != null) {
      proxyFactory.setInterfaces(this.proxyInterfaces);
   }
   else if (!isProxyTargetClass()) {
      // Rely on AOP infrastructure to tell us what interfaces to proxy.
      Class<?> targetClass = targetSource.getTargetClass();
      if (targetClass != null) {
         proxyFactory.setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
      }
   }

   // 對proxyFactory的後置處理
   postProcessProxyFactory(proxyFactory);

   // 代理工廠生成代理對象
   this.proxy = proxyFactory.getProxy(this.proxyClassLoader);
}

其中核心加強攔截器有子類實現其建立方法createMainInterceptorpost

TransactionProxyFactoryBean.java

protected Object createMainInterceptor() {
   // 初始化TransactionInterceptor
   this.transactionInterceptor.afterPropertiesSet();
   if (this.pointcut != null) {
   	  // 有pointcut的生成DefaultPointcutAdvisor
      return new DefaultPointcutAdvisor(this.pointcut, this.transactionInterceptor);
   }
   else {
      // Rely on default pointcut.
      // 沒有pointcut的依賴默認的pointcut
      return new TransactionAttributeSourceAdvisor(this.transactionInterceptor);
   }
}

TransactionAttributeSourceAdvisor的默認pointcut類是TransactionAttributeSourcePointcut,定義在其內部。學習

TransactionAttributeSourceAdvisor.java

private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
   @Override
   @Nullable
   protected TransactionAttributeSource getTransactionAttributeSource() {
      return (transactionInterceptor != null ? transactionInterceptor.getTransactionAttributeSource() : null);
   }
};

TransactionAttributeSourcePointcut是一個抽象類,在TransactionAttributeSourceAdvisor匿名實現的。咱們來看下TransactionAttributeSourcePointcut的實現,它繼承了StaticMethodMatcherPointcut,一個對方法進行匹配的基本Pointcut類,實現matches方法。ui

public boolean matches(Method method, @Nullable Class<?> targetClass) {
   if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {
      return false;
   }
   // 獲取事務屬性數據源
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 根據方法和Class對象獲取是否有事務屬性配置存在,來決定是否切入事務AOP
   return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

而事務屬性數據源從哪裏設置的呢?咱們在上面的TransactionAttributeSourceAdvisor匿名實現的TransactionAttributeSourcePointcut類中能夠發現TransactionAttributeSource是從TransactionInterceptor中獲取的。而TransactionInterceptor的TransactionAttributeSource是哪裏設置的呢?來源於XML配置的properties對象transactionAttributes,在TransactionProxyFactoryBean的setTransactionAttributes方法中。this

public void setTransactionAttributes(Properties transactionAttributes) {
   this.transactionInterceptor.setTransactionAttributes(transactionAttributes);
}

transactionAttributes實際被設置到TransactionInterceptor中線程

public void setTransactionAttributes(Properties transactionAttributes) {
   NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
   tas.setProperties(transactionAttributes);
   this.transactionAttributeSource = tas;
}

這裏看到TransactionAttributeSource的實現是NameMatchTransactionAttributeSource。在其內部維護了一個方法名和事務屬性的Map

private Map<String, TransactionAttribute> nameMap = new HashMap<>();

所以對哪一個方法進行事務AOP的切入的原理就很清楚了。接下來就是核心攔截器TransactionInterceptor的解析。

TransactionInterceptor

TransactionInterceptor實現了Spring AOP的基本增長接口MethodInterceptor,實現invoke方法

public Object invoke(final 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<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

   // Adapt to TransactionAspectSupport's invokeWithinTransaction...
   return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

具體實現由TransactionInterceptor抽象子類TransactionAspectSupport的invokeWithinTransaction方法執行

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {

   // If the transaction attribute is null, the method is non-transactional.
   // 獲取事務屬性數據源,若是爲null,則此方法爲非事務環境
   TransactionAttributeSource tas = getTransactionAttributeSource();
   // 獲取事務屬性
   final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   // 根據事務屬性決定事務管理器對象
   final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   // 鏈接點標識,通常就是方法名
   final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
      // Standard transaction demarcation with getTransaction and commit/rollback calls.
      // 建立事務對象,並返回事務信息
      TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      Object retVal = null;
      // 環繞加強實現,try中爲方法自己的執行
      try {
         // This is an around advice: Invoke the next interceptor in the chain.
         // This will normally result in a target object being invoked.
         retVal = invocation.proceedWithInvocation();
      }
      catch (Throwable ex) {
         // target invocation exception
         // 異常後的事務處理
         completeTransactionAfterThrowing(txInfo, ex);
         throw ex;
      }
      finally {
      	 // 解綁事務信息和當前線程
         cleanupTransactionInfo(txInfo);
      }
      // 方法執行成功後事務提交的處理
      commitTransactionAfterReturning(txInfo);
      return retVal;
   }
   // ...

這個方法就是事務執行的核心部分,經過環繞增長,完成方法不一樣執行結果(成功或異常)對應事務的處理。固然前提是要先建立事務,來看createTransactionIfNecessary方法

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
      @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

   // If no name specified, apply method identification as transaction name.
   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) {
         // 由事務管理器建立事務狀態對象
         status = tm.getTransaction(txAttr);
      }
      else {
         if (logger.isDebugEnabled()) {
            logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
                  "] because no transaction manager has been configured");
         }
      }
   }
   // 填充事務狀態對象的其餘信息
   return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

事務對象及狀態的維護由具體的事務管理器來管理,下一章咱們具體討論事務管理器,這裏主要關注它的構建骨架。返回的事務狀態對象TransactionStatus,須要再次被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) {
      // 記錄事務狀態
      txInfo.newTransactionStatus(status);
   }
   else {
      if (logger.isTraceEnabled())
         logger.trace("Don't need to create transaction for [" + joinpointIdentification +
               "]: This method isn't transactional.");
   }

   // We always bind the TransactionInfo to the thread, even if we didn't create
   // a new transaction here. This guarantees that the TransactionInfo stack
   // will be managed correctly even if no transaction was created by this aspect.
   // 綁定事務信息對象和當前線程,並在當前事務信息對象中記錄線程原來綁定的事務信息對象,從而保證了事務信息棧的管理
   txInfo.bindToThread();
   return txInfo;
}

這裏很是重要的是維護了一個線程級別的事務信息的棧結構。

事務信息組建完成後,就是方法自己的執行。若是發生異常,則事務該如何處理,由completeTransactionAfterThrowing方法執行

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);
      }
      // 校驗當前異常是否要回滾事務,若是是,則執行回滾操做,若是不是,則執行提交操做
      if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
         try {
            txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         }
         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 {
         // We don't roll back on this exception.
         // Will still roll back if TransactionStatus.isRollbackOnly() is true.
         try {
            txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         }
         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;
         }
      }
   }
}

在上面的方法中,核心就是判斷原始方法拋出的異常是否要回滾事務,若是是,則調用事務管理器回滾事務,若是不是,則直接提交事務。

對異常是否回滾事務的判斷是由事務屬性中的rollbackFor和noRollbackFor共同決定的,默認都沒有配置時,執行DefaultTransactionAttribute基本事務屬性類中的rollbackOn方法

public boolean rollbackOn(Throwable ex) {
   return (ex instanceof RuntimeException || ex instanceof Error);
}

即當異常爲運行時異常或Error時,就會回滾,不然直接提交。直接提交這一點也是須要格外注意的。

若是方法運行沒有異常,執行完成後,就須要提交事務,由commitTransactionAfterReturning方法執行

protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
   if (txInfo != null && txInfo.getTransactionStatus() != null) {
      if (logger.isTraceEnabled()) {
         logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
      }
      txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
   }
}

調用事務管理器執行commit來提交事務。

至此,對於TransactionProxyFactoryBean的AOP代理生成以及TransactionInterceptor核心加強中事務執行的原理都基本解析清楚了,下一章介紹事務管理器的運行機制以及DataSourceTransactionManager如何和JDBC事務接口的交互。

相關文章
相關標籤/搜索