概述
原文地址:细节知多少 - spring boot transaction解析之阶段二 访问service类的@Transactional方法实现事务的阶段
spring boot transaction我们平时用着非常简单,只需要在service方法上声明@Transactional就可以了。但是要知道,简单的背后是不简单,只是很多东西spring框架帮我们做好了。如果想进阶,想进步,想弄懂,想学习,需要接近它,了解它,弄懂它,最好的方法莫过于debug它的源码了。
笔者把spring boot transaction的整个过程分为两个阶段
- 带有@Transactional方法的service类生成代理类的阶段
- 访问service类的@Transactional方法实现事务的阶段
本文我们产出第二阶段:访问service类的@Transactional方法实现事务的阶段
技术栈
spring boot 1.5.10
spring framework 4.3.14
带着问题学习
带着问题学习往往起到更好的效果
问题:
1. 平时总是spring默认的事务只有运行时异常才回滚,为什么
2. 事务的savepoint是什么
3. 如何做到多个数据操作的事务提交和回滚的
http 访问
http://localhost:2372/user/updateSchoolName?schoolName=vl&studentId=3
当从controller访问service的方法时,因为controller引用的service指向的代理类,所以进去代理类的方法,如下
代理类的方法
这里我们以UserService的updateSchoolName为例,下面代码为UserService的updateSchoolName方法生成的代理类的方法,var10000即是DynamicAdvisedInterceptor类
final void CGLIB$updateSchoolName$4(String var1, long var2) {
super.updateSchoolName(var1, var2);
}
public final void updateSchoolName(String var1, long var2) {
try {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
var10000.intercept(this, CGLIB$updateSchoolName$4$Method, new Object[]{var1, new Long(var2)}, CGLIB$updateSchoolName$4$Proxy);
} else {
super.updateSchoolName(var1, var2);
}
} catch (Error | RuntimeException var4) {
throw var4;
} catch (Throwable var5) {
throw new UndeclaredThrowableException(var5);
}
}
从这个方法我们知道,程序会进去var10000.intercept,即DynamicAdvisedInterceptor.intercept方法,我们看看这个方法内部代码
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
Class<?> targetClass = null;
Object target = null;
try {
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
}
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
······
}
else {
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed(); // (1)
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
······
}
}
在这个方法中,会创建CglibMethodInvocation实例,proxy, target,chain等参数传给它,然后调动proceed()方法。这里运用了一个设计模式:责任链模式的变种,CglibMethodInvocation拥有一个MethodInterceptor集合,通过proceed()方法执行interceptor chain。proceed()会遍历interceptorsAndDynamicMethodMatchers(其实就是interceptor集合)从而执行每个interceptor.invoke(MethodInvocation)自身的逻辑,因为这个时候MethodInvocation会传递给invoke方法,所以每一个invoke方法内部都会执行MethodInvocation.proceed(),从而这样形成了一个链式的调用关系。我们看下链式代码结构
MethodInvocation类
public Object proceed() throws Throwable {
// 链式调用终结点
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
// 从interceptor集合中获取一个interceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
// 调用这个interceptor.invoke方法,开始走链了
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
MethodInterceptor类
public interface MethodInterceptor extends Interceptor {
Object invoke(MethodInvocation invocation) throws Throwable;
}
MethodInterceptor实现类