Spring事务部分源码解析(一)

方便谈扩展,项目引用Jdbc和RabbitMQ
源码版本spring 4.3.x

从TransactionInterceptor开始

继承关系

image.png

方法总览

image.png

从方法可以看出,我们关注点放在invoke()即可

invoke方法

image.png

图中可以看出具体实现是调用父类TransactionAspectSupport的方法

TransactionAspectSupport

继承图

image.png

子类(可以发现子类不用多说了,注解开发)

image.png

方法

image.png

可以发现,该父类已经提供了很多可用的方法

需要着重关注这两个字段

1
2
3
4
5
// 线程隔离持有(下方会谈)
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<TransactionInfo>("Current aspect-driven transaction");
// 事务管理器(下方会谈)
private PlatformTransactionManager transactionManager;

先不谈getter/setter,把重点放在根据命名比较核心的方法,总结如下

1
2
3
4
5
6
determineTransactionManager()
createTransactionIfNecessary()
prepareTransactionInfo()
invokeWithinTransaction() *
commitTransactionAfterReturning()
completeTransactionAfterThrowing()

determineTransactionManager()

image.png
image.png

通过这个方法可以发现是获取事务管理器(并放入缓存)

createTransactionIfNecessary()

image.png

通过这份方法命名可以发现是如果有必要则创建一个事务.
实际内容是获取TransactionAttribute和TransactionStatus(开启事务,AbstractPlatformTransactionManager详解),然后预处理TransactionInfo

prepareTransactionInfo()

image.png

1
2
3
4
5
6
private void bindToThread() {
// Expose current TransactionStatus, preserving any existing TransactionStatus
// for restoration after this transaction is complete.
this.oldTransactionInfo = transactionInfoHolder.get();
transactionInfoHolder.set(this);
}

通过这个方法可以发现是实例化TransactionInfo(多例)并绑定至事务持有器

invokeWithinTransaction() *

  • 表示最核心方法. ps:此方法较长无法截图因此直接放代码
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation)
throws Throwable {

// If the transaction attribute is null, the method is non-transactional.
final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
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) {
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
cleanupTransactionInfo(txInfo);
}
commitTransactionAfterReturning(txInfo);
return retVal;
}

else {
final ThrowableHolder throwableHolder = new ThrowableHolder();

// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
new TransactionCallback<Object>() {
@Override
public Object doInTransaction(TransactionStatus status) {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
}
});

// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
  1. 获取TransactionAttribute(具体实现:SpringTransactionAnnotationParser.parseTransactionAnnotation())
  2. 获取事务管理器
  3. 获取事务属性描述符
  4. 如果TransactionAttribute == null 或者事务管理器非回调
    1.1 获取处理后的TransactionInfo(开启事务)
  5. AOP执行代理方法
    1.1 发生异常执行completeTransactionAfterThrowing(),并上抛
    1.1 最终恢复当前线程旧事务(为事务嵌套预留)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    protected void cleanupTransactionInfo(TransactionInfo txInfo) {
    if (txInfo != null) {
    txInfo.restoreThreadLocalStatus();
    }
    }
    private void restoreThreadLocalStatus() {
    // Use stack to restore old transaction TransactionInfo.
    // Will be null if none was set.
    transactionInfoHolder.set(this.oldTransactionInfo);
    }
    1.1 未发生异常执行commitTransactionAfterReturning()

commitTransactionAfterReturning()

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
protected void completeTransactionAfterThrowing(TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.hasTransaction()) {
if (logger.isTraceEnabled()) {
logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
"] after exception: " + ex);
}
if (txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException ex2) {
logger.error("Application exception overridden by rollback exception", ex);
throw ex2;
}
catch (Error err) {
logger.error("Application exception overridden by rollback error", ex);
throw err;
}
}
else {
// We don't roll back on this exception.
// Will still roll back if TransactionStatus.isRollbackOnly() is true.
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (TransactionSystemException ex2) {
logger.error("Application exception overridden by commit exception", ex);
ex2.initApplicationException(ex);
throw ex2;
}
catch (RuntimeException ex2) {
logger.error("Application exception overridden by commit exception", ex);
throw ex2;
}
catch (Error err) {
logger.error("Application exception overridden by commit error", ex);
throw err;
}
}
}
}
  1. 如果TransactionInfo包含事务则执行回滚逻辑
    1.1 如果属于回滚异常范围,则执行回滚
    1.1 如果不属于回滚异常范围,则正常提交

completeTransactionAfterThrowing()

image.png

正常提交逻辑(ps: 同一个事务,如果A方法嵌套B方法,如果B方法抛出异常A捕获是否会走正常提交逻辑,如果走正常提交逻辑,事务最终是回滚还是提交? )

TransactionDefinition

image.png

子类(关注一下)
image.png

事务传播属性

TransactionAttribute

image.png

TransactionDefinition子类,增加rollbackOn(),定义回滚异常范围

TransactionStatus

image.png

传递事务状态

TransactionInfo

image.png

  1. 通过源码其实能够发现,事务提交回滚都是通过TransactionInfo.getTransactionManager().rollback()/commit()
  2. 通过源码能够发现,判断方法发生异常是否回滚是通过TransactionInfo.transactionAttribute.rollbackOn(ex)决定
  3. 通过transactionStatus传递事务相关信息
  4. 通过源码发现oldTransactionInfo是用来暂存当前线程上一个事务(感觉命名可能不是特别好,也可能个人理解不够深)

将流程串起来

  1. 获取方法Transaction配置(详细后续)
  2. 获取事务管理器(PlatformTransactionManager)
  3. 开启事务并绑定线程上下文(详情后续)
  4. 执行代理方法
  5. 异常回滚,正常提交并恢复上一个事务(详情后续)

总结

事务相关代码比较多.此篇只是先写一下基础的流程框架.具体实现放在下一篇文章(可能在这个地方还并不能关注到spring设计的优雅,慢慢来)


Spring事务部分源码解析(一)
https://gallrax.github.io/2019/09/15/Spring事务部分源码解析(一)/
作者
Gallrax
发布于
2019年9月15日
许可协议