首页 > 代码库 > Spring源码阅读:Spring声明式事务处理和编程式事务处理的设计与实现
Spring源码阅读:Spring声明式事务处理和编程式事务处理的设计与实现
之前的学习,了解了Spring事务管理的基础框架(查看)。Spring在此基础上又提到了声明式事务管理和编程式事务管理。这里就来看看Spring是如何实现的。
Spring声明式事务与EJB事务管理对比
Spring的声明式管理,类似于EJB的CMT,但又有不同。他们的不同之处有:
1)EJB的CMT是与JTA结合使用,而Spring框架的声明式事务管理可以在任何环境下工作。既可以使用全局事务管理,如JTA,也可以使用局部事务管理如JDBCJPA、Hibernate、JDO等。
2)可以在任何类中使用Spring的声明式事务管理。但EJB就不行,它只能在特定的类中使用。
3)Spring中提供了一些与EJB中不同的回滚原则(都有回滚原则,但Spring中有些是与EJB中不同的)。这些回滚原则在编程式事务管理和声明式事务管理中都是可用的。
4)Spring框架可以让你使用AOP方式自定义一些事务行为。而在EJB中,是不可以的。
5)Spring框架不支持远程调用的事务传播机制上下文。如果应用中需要支持在远程调用时的事务传播机制,需要使用EJB了。
Spring声明式事务管理
Spring声明式事务管理,是采用AOP原理实现(查看)的。之前看Spring AOP的源码时知道,Spring AOP是通过创建代理(CGI代理或者JDK代理(查看)),代理调用AOP拦截器链,然后调用真实的处理,返回结果。
接下来看看Spring声明式事务管理是如何实现的:
根据上图,可以猜测:Caller执行方法调用时,先Spring容器为其创建AOP代理,根据代理获取到它的拦截器,调用拦截器链处理,然后进行方法调用,最后拦截器链做后置处理,并返回结果。
事务管理是作为一个Advistor出现的,Advistor,就是Advice的持有者,通过它就能找到Advice,也就是够找到Interceptor,所以就简单的理解为Spring是把事务处理作为一个拦截器放置在其他的拦截器前面。
上面是根据调用流程图猜测的,接下来看看Spring中是如何处理的:
TransactionAttributeSourceAdvistor就是上面原理图中的Advistor,也是SpringAOP要用的Advistor。在他的内部,的确是有一个拦截器TransactionInterceptor。接下来看看这个拦截器(只看主要部分):
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {public Object invoke(final MethodInvocation invocation) throws Throwable { // Work out the target class: may be <code>null</code>. // 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); // If the transaction attribute is null, the method is non-transactional. final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(invocation.getMethod(), targetClass);// 取到PlatformTransactionManager事务管理对象 final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(invocation.getMethod(), targetClass); 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 { // This is an around advice: Invoke the next interceptor in the chain. // This will normally result in a target object being invoked.// 调用拦截器链其他的拦截器(AOP建议)处理,最后调用target方法 retVal = invocation.proceed(); } catch (Throwable ex) { // target invocation exception// 必要时抛出异常 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { cleanupTransactionInfo(txInfo); }// 事务提交 commitTransactionAfterReturning(txInfo); return retVal; } else {// 针对WebsphereUowTransactionManager的处理。 // It‘s a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in. try { Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, new TransactionCallback<Object>() { public Object doInTransaction(TransactionStatus status) { TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status); try { return invocation.proceed(); } catch (Throwable ex) { if (txAttr.rollbackOn(ex)) { // A RuntimeException: will lead to a rollback. if (ex instanceof RuntimeException) { throw (RuntimeException) ex; } else { throw new ThrowableHolderException(ex); } } else { // A normal return value: will lead to a commit. return new ThrowableHolder(ex); } } finally { cleanupTransactionInfo(txInfo); } } }); // Check result: It might indicate a Throwable to rethrow. if (result instanceof ThrowableHolder) { throw ((ThrowableHolder) result).getThrowable(); } else { return result; } } catch (ThrowableHolderException ex) { throw ex.getCause(); } } }}
显而易见,这里的代码验证了我对于上面的Spring事务处理模型图猜测的正确性。这样得益于之前的对于AOP的理解(查看,查看)。另外如果没有之前的源码学习,而直接看这部分,是很难理解的。
从这部分源码中,看到了Spring默认的就帮助我们处理了异常。所以我们在写代码时,可以不做异常处理的。
声明式事务处理的两种配置方式
因为声明式事务处理底层是使用AOP实现的。所以在项目 中可以有两种配置声明式事务处理的方式:使用XML或者使用@Transactional
使用XML方式配置:
注解方式配置:
在代码中 加入注解就行了:
对于readonly,proagation等属性的理解配置,上一篇博客(查看)中已经学习了。
Spring编程式事务管理
顾名思义,就是我们处理业务逻辑时自己写有关事务处理的代码。
在做Spring编程式事务处理时,Spring依旧使用了模板方法模式,这个模式Spring是屡试不爽呀。
上一篇文章中也说了Spring推荐使用TransactionTemplate来完成处理编程式事务处理。看看模板方法中是怎么写的:
public <T> T execute(TransactionCallback<T> action) throws TransactionException { if (this.transactionManager instanceof CallbackPreferringPlatformTransactionManager) { return ((CallbackPreferringPlatformTransactionManager) this.transactionManager).execute(this, action); } else { TransactionStatus status = this.transactionManager.getTransaction(this); T result; try { result = action.doInTransaction(status); } catch (RuntimeException ex) { // Transactional code threw application exception -> rollback rollbackOnException(status, ex); throw ex; } catch (Error err) { // Transactional code threw error -> rollback rollbackOnException(status, err); throw err; } catch (Exception ex) { // Transactional code threw unexpected exception -> rollback rollbackOnException(status, ex); throw new UndeclaredThrowableException(ex, "TransactionCallback threw undeclared checked exception"); } this.transactionManager.commit(status); return result; } }
采用了带有回调函数的模板方法来处理(不理解可以参考模板方法模式)。我们在回调函数中写上要进行事务处理实际的业务逻辑代码就行了。这个模板替我们做了两件事:1)事务的管理,2)异常的处理。
我们使用时,只需如此:
在使用编程式事务处理式,也可以直接的使用PlatformTransactionManager的实现类来完成上述操作:
例如
这个就不详细说明了,这个与上节中的知识也是紧密相关的。由于写起来比较麻烦,并不推荐使用。
如何选择?
如果你的项目比较小,只有少量的Update操作时,可以采用编程式事务处理,即使用TransactionTemplate即可。除此之外,还是推荐使用声明式事务处理,方便,只需要集中处理业务逻辑即可。
当然要用好声明式事务处理,上一篇博客中的内容可以是很重要的哟。