目录

18 声明式事务注解@Transaction的解析原理

目录

spring源码系列文章,示例代码的中文注释,均是 copy 自 https://gitee.com/wlizhi/spring-framework

链接中源码是作者从 github 下载,并以自身理解对核心流程及主要节点做了详细的中文注释。


[17 声明式事务执行流程源码分析] 中已经列举,通过 getTransactionAttribute() 获取到了方法上事务注解的一些信息。

来到其源码:

 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
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
    public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 获取事务注解属性
		if (method.getDeclaringClass() == Object.class) {
			return null;
		}

		// 先从缓存中拿。如果一个方法的事务注解信息被获取过,就会将其缓存到一个并发安全的map中。后面再获取就从这个缓存中获取。
		// First, see if we have a cached value.
		Object cacheKey = getCacheKey(method, targetClass);
		TransactionAttribute cached = this.attributeCache.get(cacheKey);
		if (cached != null) {
			// 省略...
		}else {
			// TODO 获取事务注解属性,放入缓存。
			// We need to work it out.
			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);
				// 省略...
				this.attributeCache.put(cacheKey, txAttr);
			}
			return txAttr;
		}
	}
}

先从缓存中获取,如果可以获取到直接返回。否则调用 computeTransactionAttribute() 从方法上进行事务注解信息的获取。

来到 computeTransactionAttribute() 源码:

 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
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {

	protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// Don't allow no-public methods as required.
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}

		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// TODO 重点:查找事务属性,首先从目标方法上查找
		// First try is the method in the target class.
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}
		// 如果目标方法上查找不到,从目标类上查找。
		// Second try is the transaction attribute on the target class.
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}
		// 如果方法上找不到,到接口方法、接口上找对应注解。
		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		return null;
	}
}

查找注解信息的顺序:

  1. 从缓存中获取,如果获取得到,就返回。
  2. 从目标对象的方法上找,如果能查找到注解信息,就返回。
  3. 从目标对象类上查找注解信息,如果查找到,就返回。
  4. 从目标接口、父类方法上查找注解信息,如果查找到,就返回。
  5. 从目标接口、父类上查找注解信息,如果查找到,就返回。
  6. 如果没有查找到注解信息,就返回null。

继续向下追踪源码就能看到,无论是从方法上获取、还是从类上获取注解信息,最终都是调用到 determineTransactionAttribute()。

源码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
		implements Serializable {
    protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
		// TODO 循环所有的解析器,如果有解析器解析出的结果不为空,则直接返回事务属性,解析器列表是在当前对象构造函数时,加载的
		//  如果是注解方式,用到的注解解析器是:SpringTransactionAnnotationParser
		for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
			TransactionAttribute attr = annotationParser.parseTransactionAnnotation(element);
			if (attr != null) {
				return attr;
			}
		}
		return null;
	}
}

遍历 annotationParsers,并调用 preTransactionAnnotation(),在 [14 声明式事务中XML配置及注解方式的注册入口] 中已经说明,在事务注解支持的入口,注册了 AnnotationTransactionAttributeSource,其中封装了一个解析类 SpringTransactionAnnotationParser,这个类就负责事务注解的解析。

SpringTransactionAnnotationParser 是 TransactionAnnotationParser 的其中一个实现。

以下是 SpringTransactionAnnotationParser.parseTransactionAnnotation() 源码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	@Override
	@Nullable
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {

		// TODO 重点:从方法上查找@Transactional注解,AnnotatedElement是Method、Field的超类
		AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
				element, Transactional.class, false, false);
		if (attributes != null) {
			// TODO 重点:如果从方法上查找到了@Transactional注解,则解析注解中的各个属性值
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}
}

AnnotatedElement是 Method、Class的共同父类,是一个接口。

上面源码中,首先从方法、或者类上查找 @Transactional 注解,如果查找到,调用 parseTransactionAnnotation(),进行解析封装。

 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
public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
		// TODO 此方法主要做对象类型转换,将AnnotationAttributes中的属性赋值到RuleBasedTransactionAttribute中,返回。
		RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
		// 解析 @Transactional 中的属性:propagation、isolation、timeout、readOnly、value。
		// 解析后将其封装到 RuleBasedTransactionAttribute 对象中。
		Propagation propagation = attributes.getEnum("propagation");
		rbta.setPropagationBehavior(propagation.value());
		Isolation isolation = attributes.getEnum("isolation");
		rbta.setIsolationLevel(isolation.value());
		rbta.setTimeout(attributes.getNumber("timeout").intValue());
		rbta.setReadOnly(attributes.getBoolean("readOnly"));
		rbta.setQualifier(attributes.getString("value"));

		List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
		for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
			rollbackRules.add(new RollbackRuleAttribute(rbRule));
		}
		for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
			rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
		}
		rbta.setRollbackRules(rollbackRules);

		return rbta;
	}
}

创建一个 RuleBasedTransactionAttribute,依次解析注解中 propagation、isolation、timeout、readOnly、value 等属性,将其封装到 RuleBasedTransactionAttribute 中返回。

最终返回后,会放入到 attributeCache 中,后面在获取,就会从缓存中获取。