Spring源码解析之事务篇
您目前处于:编程  2017年11月06日

Spring事务是我们日常工作中经常使用的一项技术,Spring提供了编程、注解、aop切面三种方式供我们使用Spring事务,其中编程式事务因为对代码入侵较大所以不被推荐使用,注解和aop切面的方式可以基于需求自行选择,我们以注解的方式为例来分析Spring事务的原理和源码实现。

首先我们简单看一下Spring事务的使用方式,配置:

<tx:annotation-driven transaction-manager="transactionManager"/>
 <bean id="transactionManager" 
         class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
     <property name="dataSource" ref="dataSource"/>
 </bean>

在需要开启事务的方法上加上@Transactional注解即可,这里需要注意的是,当<tx:annotation-driven/>标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器,如果没有id为transactionManager的bean并且在使用@Transactional注解时也没有指定value(事务管理器),程序就会报错。当我们在配置两个以上的<tx:annotation-driven/>标签时,如下:

<tx:annotation-driven transaction-manager="transactionManager1"/>
<bean id="transactionManager1" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource1"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager2"/>
<bean id="transactionManager2" 
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource2"/>
</bean>

这时第一个<tx:annotation-driven/>会生效,也就是当我们使用@Transactional注解时不指定事务管理器,默认使用的事务管理器是transactionManager1,后文分析源码时会具体提到这些注意点。

下面我们开始分析Spring的相关源码,首先看一下对<tx:annotation-driven/>标签的解析,这里需要读者对Spring自定义标签解析的过程有一定的了解,笔者后续也会出相关的文章。锁定TxNamespaceHandler:

(右键可查看大图)

这个方法比较长,关键的部分做了标记,最外围的if判断限制了<tx:annotation-driven/>标签只能被解析一次,所以只有第一次被解析的标签会生效。蓝色框的部分分别注册了三个BeanDefinition,分别为AnnotationTransactionAttributeSource、TransactionInterceptor和BeanFactoryTransactionAttributeSourceAdvisor,并将前两个BeanDefinition添加到第三个BeanDefinition的属性当中,这三个bean支撑了整个事务功能,后面会详细说明。我们先来看红色框的第个方法:

还记得当<tx:annotation-driven/>标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器这个注意事项么,就是在这里实现的。下面我们来看红色框的第二个方法:

这两个方法的主要目的是注册InfrastructureAdvisorAutoProxyCreator,注册这个类的目的是什么呢?我们看下这个类的层次:

我们发现这个类间接实现了BeanPostProcessor接口,我们知道,Spring会保证所有bean在实例化的时候都会调用其postProcessAfterInitialization方法,我们可以使用这个方法包装和改变bean,而真正实现这个方法是在其父类AbstractAutoProxyCreator类中:

上面这个方法相信大家已经看出了它的目的,先找出所有对应Advisor的类的beanName,再通过beanFactory.getBean方法获取这些bean并返回。不知道大家还是否记得在文章开始的时候提到的三个类,其中BeanFactoryTransactionAttributeSourceAdvisor实现了Advisor接口,所以这个bean就会在此被提取出