寻找源码
首先我们从
@Transactional
注解出发。查看引用,可以看到有个名叫
SpringTransactionAnnotationParser
的类比较可疑,根据名字理解,作用就是用来解析@Transactional
注解的。我们定位到这个方法,可以看到它实际上就是在获取注解上的属性。(下面的几个方法是根据方法引用链一步步往上找的)
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
57
58
59
60
61
62// SpringTransactionAnnotationParser#parseTransactionAnnotation
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new 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());
String timeoutString = attributes.getString("timeoutString");
Assert.isTrue(!StringUtils.hasText(timeoutString) || rbta.getTimeout() < 0,
"Specify 'timeout' or 'timeoutString', not both");
rbta.setTimeoutString(timeoutString);
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
rbta.setLabels(Arrays.asList(attributes.getStringArray("label")));
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;
}
// SpringTransactionAnnotationParser#parseTransactionAnnotation
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
element, Transactional.class, false, false);
if (attributes != null) {
return parseTransactionAnnotation(attributes);
}
else {
return null;
}
}
// AnnotationTransactionAttributeSource#determineTransactionAttribute
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}然后定位到了
AnnotationTransactionAttributeSource
这个类,里面有这两个方法。根据名称不难理解,一个是寻找类上的@Transactional
注解,一个是寻找方法上的@Transactional
注解。1
2
3
4
5
6
7
8
9
10
11@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}然后这两个方法具体在
AbstractFallbackTransactionAttributeSource
这个类中被引用。下面是这个类的三个方法,注意下,这个类和上面的那个类AnnotationTransactionAttributeSource
是有继承关系的,很明显,这里使用到了一个模板方法模式。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@Nullable
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);
// 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;
}
@Nullable
protected abstract TransactionAttribute findTransactionAttribute(Class<?> clazz);
/**
* Subclasses need to implement this to return the transaction attribute for the
* given method, if any.
* @param method the method to retrieve the attribute for
* @return all transaction attribute associated with this method, or {@code null} if none
*/
@Nullable
protected abstract TransactionAttribute findTransactionAttribute(Method method);再次寻找引用,可以定位到一个这个类中的
AbstractFallbackTransactionAttributeSource#getTransactionAttribute
方法。再次寻找这个方法的引用。可以到如下结果:这时候,我们定位到了两个和切面相关的词语,Aspect和PointCut。那说明我们已经差不多找到切面了。
最后,我们定位到了
TransactionAspectSupport
这个类,就是实现我们@Transactional
功能的一个核心类的。然后我们开始源码的分析。
源码分析
TransactionAspectSupport
这个类的重点方法在invokeWithinTransaction
上。名字很直接了,在事务里执行。而这个方法又被
TransactionInterceptor#invoke
调用。TransactionInterceptor
的类签名如下:1
2
3public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable{
// other code
}可以看到,它实现了一个
MethodInterceptor
接口,而这个接口就是Spring为我们提供的AOP接口。所以八股文常说@Transactional
是基于AOP实现的,原因就在这儿。于是我们对重点方法
TransactionAspectSupport#invokeWithinTransaction
进行分析,以注释的形式。这里说白了就是根据不同的事务管理器类型,去执行不同的操作。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@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
TransactionAttributeSource tas = getTransactionAttributeSource();
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 根据注解上的配置来选择使用的事务管理器。
final TransactionManager tm = determineTransactionManager(txAttr);
if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
// 便于查看,忽略代码,位置1。
}
PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 便于查看,忽略代码,位置2。
}
else {
// 便于查看,忽略代码,位置3。
}
}由于不同版本的SB这个源码有点变化,本文基于:2.4.3,所以这里只分析位置2的代码。
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
33if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
// 如果没有事务就创建事务,创建的事务,会从数据库连接池中获取连接,通过ThreadLoacl放入当前线程中,并设置connect.setAutoCommit= false
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);
Object retVal;
try {
// 调用目标方法
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// 如果目标方法抛异常,那么进行回滚。主要根据TransactionAttribute.rollbackOn(Throwable)来判断是否回滚,默认实现应该是RuleBasedTransactionAttribute,也就是注解中设置的rollbackFor那些,当然也有其他处理,建议点开方法去看。
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
if (retVal != null && vavrPresent && VavrDelegate.isVavrTry(retVal)) {
// Set rollback-only in case of Vavr failure matching our rollback rules...
TransactionStatus status = txInfo.getTransactionStatus();
if (status != null && txAttr != null) {
retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
}
}
// 如果目标方法正常运行,提交事务
commitTransactionAfterReturning(txInfo);
return retVal;
}
其他
- 这里只对
@Transactional
的基本实现原理进行了源码分析,至于传播行为是怎么设置的,建议此处只给出方法位置,就不具体做分析了,建议自己打断点调。- 传播行为:处理位于
AbstractPlatformTransactionManager#handleExistingTransaction
,主要用于AbstractPlatformTransactionManager#getTransaction
方法。
- 传播行为:处理位于
总结
- 这里简单的对SB中
@Transactional
的源码进行了分析,可以明确的知道的是SB中的事务是基于 SB自带的MethodInterceptor
来实现的,而MethodInterceptor
又是SB中AOP的实现,所以要想事务生效,除了注意配置rollbackFor
、隔离级别、传播行为等基本条件,还需要满足当前代理框架(JDK动态代理或CGLIB)的基本条件,才能保证事务生效(类或方法不能是final,方法不能是private啥的)。