我们看看Spring中的事务处理的代码,使用Spring管理事务有声明式和编程式两种方式,声明式事务处理通过AOP的实现把事物管理代码作为方面封装来横向插入到业务代码中,使得事务管理代码和业务代码解藕。在这种方式我们结合IoC容器和Spirng已有的FactoryBean来对事务管理进行属性配置,比如传播行为,隔离级别等。其中最简单的方式就是通过配置TransactionProxyFactoryBean来实现声明式事物;
在整个源代码分析中,我们可以大致可以看到Spring实现声明式事物管理有这么几个部分:
- 对在上下文中配置的属性的处理,这里涉及的类是TransactionAttributeSourceAdvisor,这是一个通知器,用它来对属性值进行处理,属性信息放在TransactionAttribute中来使用,而这些属性的处理往往是和对切入点的处理是结合起来的。对属性的处理放在类TransactionAttributeSource中完成。
- 创建事物的过程,这个过程是委托给具体的事物管理器来创建的,但Spring通过TransactionStatus来传递相关的信息。
- 对事物的处理通过对相关信息的判断来委托给具体的事物管理器完成。
我们下面看看具体的实现,在TransactionFactoryBean中:
1 | public class TransactionProxyFactoryBean extends AbstractSingletonProxyFactoryBean |
那什么时候Spring的TransactionInterceptor被注入到Spring AOP中成为Advisor中的一部分呢?我们看到在TransactionProxyFactoryBean中,这个方法在IOC初始化bean的时候被执行:
1 | public void afterPropertiesSet() { |
Spring 已经定义了一个transctionInterceptor作为拦截器或者AOP advice的实现,在IOC容器中定义的其他属性比如transactionManager和事务管理的属性都会传到已经定义好的 TransactionInterceptor那里去进行处理。以上反映了基本的Spring AOP的定义过程,其中pointcut和advice都已经定义好,同时也通过通知器配置到ProxyFactory中去了。
下面让我们回到TransactionProxyFactoryBean中看看TransactionAttributeSourceAdvisor是怎样定义的,这样我们可以理解具体的属性是怎样起作用,这里我们分析一下类TransactionAttributeSourceAdvisor:
1 | public class TransactionAttributeSourceAdvisor extends AbstractPointcutAdvisor { |
这里我们看看属性值是怎样被读入的:AbstractFallbackTransactionAttributeSource负责具体的属性读入任务,我们可以有两种读入方式,比如annotation和直接配置.我们下面看看直接配置的读入方式,在Spring中同时对读入的属性值进行了缓存处理,这是一个decorator模式:
1 | public final TransactionAttribute getTransactionAttribute(Method method, Class targetClass) { |
别急,基本的处理在computeTransactionAttribute()中:
1 | private TransactionAttribute computeTransactionAttribute(Method method, Class targetClass) { |
经过一系列的尝试我们可以通过findTransactionAttribute()通过调用findAllAttribute()得到TransactionAttribute的对象,如果返回的是null,这说明该方法不是我们需要事务处理的方法。
在完成把需要的通知器加到ProxyFactory中去的基础上,我们看看具体的看事务处理代码怎样起作用,在TransactionInterceptor中:
1 | public Object invoke(final MethodInvocation invocation) throws Throwable { |
这里面涉及到事务的创建,我们可以在TransactionAspectSupport实现的事务管理代码:
1 | protected TransactionInfo createTransactionIfNecessary( |
首先通过TransactionManager得到需要的事务,事务的创建根据我们定义的事务配置决定,在 AbstractTransactionManager中给出一个标准的创建过程,当然创建什么样的事务还是需要具体的 PlatformTransactionManager来决定,但这里给出了创建事务的模板:
1 | public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException { |
接着通过调用prepareTransactionInfo完成事务创建的准备,创建过程中得到的信息存储在TransactionInfo对象中进行传递同时把信息和当前线程绑定;
1 | protected TransactionInfo prepareTransactionInfo( |
将创建事务的信息返回,然后看到其他的事务管理代码:
1 | protected void commitTransactionAfterReturning(TransactionInfo txInfo) { |
通过transactionManager对事务进行处理,包括异常抛出和正常的提交事务,具体的事务管理器由用户程序设定。
1 | protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) { |
Spring通过以上代码对transactionManager进行事务处理的过程进行了AOP包装,到这里我们看到为了方便客户实现声明式的事务处理,Spring还是做了许多工作的。如果说使用编程式事务处理,过程其实比较清楚,我们可以参考书中的例子:
1 | TransactionDefinition td = new DefaultTransactionDefinition(); |
我们看到这里选取了默认的事务配置DefaultTransactionDefinition,同时在创建事物的过程中得到TransactionStatus,然后通过直接调用事务管理器的相关方法就能完成事务处理。
声明式事务处理也同样实现了类似的过程,只是因为采用了声明的方法,需要增加对属性的读取处理,并且需要把整个过程整合到Spring AOP框架中和IoC容器中去的过程。
下面我们选取一个具体的transactionManager - DataSourceTransactionManager来看看其中事务处理的实现:
同样的通过使用AbstractPlatformTransactionManager使用模板方法,这些都体现了对具体平台相关的事务管理器操作的封装,比如commit:
1 | public final void commit(TransactionStatus status) throws TransactionException { |
通过对TransactionStatus的具体状态的判断,来决定具体的事务处理:
1 | private void processCommit(DefaultTransactionStatus status) throws TransactionException { |
这些模板方法的实现由具体的transactionManager来实现,比如在DataSourceTransactionManager:
1 | protected void doCommit(DefaultTransactionStatus status) { |
我们看到在DataSourceTransactionManager中最后还是交给connection来实现事务的提交和rollback。整个声明式事务处理是事务处理在Spring AOP中的应用,我们看到了一个很好的使用Spring AOP的例子,在Spring声明式事务处理的源代码中我们可以看到:
- 怎样封装各种不同平台下的事务处理代码
- 怎样读取属性值和结合事务处理代码来完成既定的事务处理策略
- 怎样灵活的使用SpringAOP框架。
如果能够结合前面的Spring AOP的源代码来学习,理解可能会更深刻些。