再分析完AOP之后,趁热打铁,再分析一下Spring的事务处理。
因为一直都是使用SpringBoot,所以用@EnableTransactionManagement和@Transactional就可以实现简单的例子,但是感觉不太直观,所以本文采用xml的配置来分析事务。

首先贴个简单的配置文件,包含支持十五注解的标签,还有事务管理器和一个半成品dataSource。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 支持事务注解-->
<tx:annotation-driven transaction-manager="txManager"/>
<!-- 配置事务管理器 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 需要增强的类,即里面有个public方法要用@Transactional修饰 -->
<bean id="customTxService" class="com.demo.CustomTxService"/>

<!--设定 dataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
</bean>

定义一个事务方法,这里面的mapper随便写的。

1
2
3
4
5
6
7
8
9
10
11
public class CustomTxService {

@Transactional
public int sum(int num) {
// 使用mybatis mapper来操作数据库
int result = customMapper.insert(num);
// 抛出RuntimeException,事务回滚
int i = 1 / 0;
return result;
}
}

最后方法调用:

1
2
3
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-tx.xml");
CustomTxService bean = context.getBean("customTxService", CustomTxService.class);
bean.sum(2)

首先要解析xml中的自定义标签:<tx:annotation-driven transaction-manager=”txManager”/>
找到org.springframework.transaction.config.TxNamespaceHandler类:

1
2
3
4
5
6
@Override
public void init() {
registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
}

即AnnotationDrivenBeanDefinitionParser类负责解析annotation-driven标签:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* Parses the {@code <tx:annotation-driven/>} tag. Will
* {@link AopNamespaceUtils#registerAutoProxyCreatorIfNecessary register an AutoProxyCreator}
* with the container as necessary.
*/
@Override
@Nullable
public BeanDefinition parse(Element element, ParserContext parserContext) {
registerTransactionalEventListenerFactory(parserContext);
String mode = element.getAttribute("mode");
//使用AspectJ织入的模式
if ("aspectj".equals(mode)) {
// mode="aspectj"
registerTransactionAspect(element, parserContext);
if (ClassUtils.isPresent("javax.transaction.Transactional", getClass().getClassLoader())) {
registerJtaTransactionAspect(element, parserContext);
}
}
else {
// mode="proxy"
//代理模式
AopAutoProxyConfigurer.configureAutoProxyCreator(element, parserContext);
}
return null;
}

因为我这没有配置mode,所以走代理模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/**
* 当实际处于代理模式时,只引入AOP框架依赖项的内部类。
*/
private static class AopAutoProxyConfigurer {

public static void configureAutoProxyCreator(Element element, ParserContext parserContext) {
//在这里注入InfrastructureAdvisorAutoProxyCreator实例(org.springframework.transaction.config.internalTransactionAdvisor),
// 这一步和分析AOP的时候很相似,那时候注入的是AnnotationAwareAspectJAutoProxyCreator
// 都是在bean实例化的时候调用postProcessAfterInitialization方法,增强bean的方法。
// 从这就可以看出AOP的设计思路真的很强大
AopNamespaceUtils.registerAutoProxyCreatorIfNecessary(parserContext, element);

//事务增强器名称
String txAdvisorBeanName = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME;
//不包含事务增强器的bean定义
if (!parserContext.getRegistry().containsBeanDefinition(txAdvisorBeanName)) {
Object eleSource = parserContext.extractSource(element);

// 创建TransactionAttributeSource定义。用于处理JDK 1.5+注释格式的事务元数据的接口。
RootBeanDefinition sourceDef = new RootBeanDefinition(
"org.springframework.transaction.annotation.AnnotationTransactionAttributeSource");
sourceDef.setSource(eleSource);
sourceDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
String sourceName = parserContext.getReaderContext().registerWithGeneratedName(sourceDef);

// 创建TransactionInterceptor定义。
// 使用公共Spring事务基础设施PlatformTransactionManager进行声明性事务管理的AOP Alliance MethodInterceptor。
RootBeanDefinition interceptorDef = new RootBeanDefinition(TransactionInterceptor.class);
interceptorDef.setSource(eleSource);
interceptorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

// 注册事务管理器,会读取transaction-manager属性
registerTransactionManager(element, interceptorDef);
interceptorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
String interceptorName = parserContext.getReaderContext().registerWithGeneratedName(interceptorDef);

// 创建TransactionAttributeSourceAdvisor定义。
// 事务增强器
RootBeanDefinition advisorDef = new RootBeanDefinition(BeanFactoryTransactionAttributeSourceAdvisor.class);
advisorDef.setSource(eleSource);
advisorDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
advisorDef.getPropertyValues().add("transactionAttributeSource", new RuntimeBeanReference(sourceName));
advisorDef.getPropertyValues().add("adviceBeanName", interceptorName);
if (element.hasAttribute("order")) {
advisorDef.getPropertyValues().add("order", element.getAttribute("order"));
}
parserContext.getRegistry().registerBeanDefinition(txAdvisorBeanName, advisorDef);

CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(), eleSource);
compositeDef.addNestedComponent(new BeanComponentDefinition(sourceDef, sourceName));
compositeDef.addNestedComponent(new BeanComponentDefinition(interceptorDef, interceptorName));
compositeDef.addNestedComponent(new BeanComponentDefinition(advisorDef, txAdvisorBeanName));
parserContext.registerComponent(compositeDef);
}
}
}

总的来说就是用Spring AOP实现了事务的统一管理,通过注册InfrastructureAdvisorAutoProxyCreator,在bean初始化的时候对bean进行增强。
通过InfrastructureAdvisorAutoProxyCreator获取到当前的Advisor:BeanFactoryTransactionAttributeSourceAdvisor,和当前的Pointcut:TransactionAttributeSourcePointcut。

在调用TransactionAttributeSourcePointcut的match方法来获取要增强的方法,即被被@Transactional修饰的方法,这里会使用AnnotationTransactionAttributeSource的getTransactionAttribute解析。
TransactionAttributeSourcePointcut的match方法用于过滤当前bean是否需要增强:

1
2
3
4
5
6
7
8
9
10
@Override
public boolean matches(Method method, Class<?> targetClass) {
if (TransactionalProxy.class.isAssignableFrom(targetClass) ||
PlatformTransactionManager.class.isAssignableFrom(targetClass) ||
PersistenceExceptionTranslator.class.isAssignableFrom(targetClass)) {
return false;
}
TransactionAttributeSource tas = getTransactionAttributeSource();
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

AnnotationTransactionAttributeSource解析在其父类AbstractFallbackTransactionAttributeSource中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
/**
* 确定此方法调用的事务属性。
* 如果没有找到方法属性,则默认为该类的事务属性。
*
* @param method 当前调用的方法(绝不是{@code null})
* @param targetClass 这个调用的目标类(可能是{@code null})
* @return 此方法的TransactionAttribute,如果该方法不是事务性的,则为{@code null}
*/
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
if (method.getDeclaringClass() == Object.class) {
return null;
}

// 首先,看看是否有缓存值。
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
// 值将是指示没有事务属性的规范值,或者是实际的事务属性。
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
} else {
return cached;
}
}
//没有缓存
else {
// 重要方法
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
// Put it in the cache.

//如果没有事务属性
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
//如果有事务属性
else {
//设置描述
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}

进入核心方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/**
* 与{@link #getTransactionAttribute}相同的签名,但不缓存结果。
* {@link #getTransactionAttribute}是这个方法的缓存装饰器。
* <p>从4.1.8开始,可以重写此方法。
*
* @see #getTransactionAttribute
* @since 4.1.8
*/
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 不允许使用非公共方法。即:将@Transactional注解标注在非public方法上是不会生效的
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}

// 方法可能在接口上,但是我们需要目标类的属性。
// 如果目标类为空,则方法将保持不变。
// 能从代理对象上的一个方法,找到真实对象上对应的方法。
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

// 首先尝试的是目标类中的方法。这个是比较重要的方法。
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}

// 第二个尝试是目标类上的事务属性。
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}

if (specificMethod != method) {
// 后退是查看原始方法。
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// 最后一个回退是原始方法的类。
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}

return null;
}

从这可知会去解析方法上的注解,如果没有的话解析类上的注解。
findTransactionAttribute(Method method)与findTransactionAttribute(Class<?> clazz)最终会调用AnnotationTransactionAttributeSource中的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
//这里有可能会有三个Parser解析
//Ejb3TransactionAnnotationParser
//JtaTransactionAnnotationParser
//SpringTransactionAnnotationParser
for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
//调用解析
TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}

这里以SpringTransactionAnnotationParser为例子:

1
2
3
4
5
6
7
8
9
10
11
12
@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;
}
}

就分析到这一层好了,最终过滤出了当前的bean是否应该被增强。

总结一下本篇的流程:

  • 用一个假的例子来示范事务的使用;
  • 解析xml文件,解析tx:annotation-driven/标签
  • 注入InfrastructureAdvisorAutoProxyCreator便于在目标bean实例化的时候增强
  • 配置Advisor:BeanFactoryTransactionAttributeSourceAdvisor,和Pointcut:TransactionAttributeSourcePointcut,用于匹配和处理事务增强操作。
  • 使用AnnotationTransactionAttributeSource来解析@Transaction注解的方法或者类

下一篇在分析到底是如何事务增强的。

tencent.jpg