springboot 事务执行全流程分析
目录在上篇文章springboot 事务创建流程源码分析中主要讲了springboot事务创建的过程,本次我们来看看事务具体执行的过程。
这里关于几个名称提前先达成一致:
com.springboot.transaction.service.impl.UserServiceImpl这个类我们称它为原始类,它的对象我们称原始对象
springboot通过aop生成的com.springboot.transaction.service.impl.UserServiceImpl的子类,我们称它为代理类,它的对象我们称代理对象
在main方法中会有这一句
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,p);
这里的p是设置的springboot动态生成代码的本地保存位置,在生成代理类中,我们就可以在这里找到对应的所有动态代理类的class文件,通过反编译,我们也能了解更多的信息为了避免其他框架对事务执行的干扰,本篇文章数据库使用的是原生的jdbctemplate。主要是其他框架,类似mybatis之类,在事务过程中也会插入自己框架的代码。
本篇博客的源码路径:https://github.com/wbo112/blogdemo/tree/main/springbootdemo/springboot-jdbc-transaction
1. 事务方法执行前的准备工作
在服务启动后,我们在浏览器中输入http://localhost:8080/addUser来请求后台。就会请求到com.springboot.transaction.jdbc.controller.UserController的addUsers方法,具体会执行到return userService.addUser();
这句代码,这里的userService就是上篇文章中讲到的代理类,这就会调用到代理类中的addUser方法。
上篇文章我们也贴出来了反编译的userService代理类,具体会调到下面的代码
//代理类中的方法
public final boolean addUser() {
//这里的this.CGLIB$CALLBACK_0,就是上篇文章中讲到的在最终生成代理类后调用setCallbacks方法赋值的
//这里的this.CGLIB$CALLBACK_0就是CglibAopProxy$DynamicAdvisedInterceptor
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
//CGLIB$addUser$0$Method是原始类的方法public boolean com.springboot.transaction.jdbc.service.impl.UserServiceImpl.addUser()
//CGLIB$addUser$0$Proxy是MethodProxy类的对象,最终的调用就是通过MethodProxy.invoke来完成的
if (var10000 != null) {
Object var1 = var10000.intercept(this, CGLIB$addUser$0$Method, CGLIB$emptyArgs, CGLIB$addUser$0$Proxy);
return var1 == null ? false : (Boolean)var1;
} else {
return super.addUser();
}
}
上面的代码就会调用到CglibAopProxy$DynamicAdvisedInterceptor的intercept方法,我们继续进到这个里面去看看
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
//这里会获取我们的原始对象和原始类
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//这里会获取具体需要执行拦截的拦截器列表,我们这里只会有一个org.springframework.transaction.interceptor.TransactionInterceptor的对象,这个也是在上篇文章中有讲到,是作为一个bean对象加载的
//这里的this.advised是org.springframework.aop.framework.ProxyFactory的对象,关于这个类在上篇文章中有过描述,这里就不再说类
//我们先进到这个方法里面去看看拦截器列表是如何获取到的
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
//在这里就会去生成CglibMethodInvocation对象,并通过调用process来完成整个事务过程的处理的。
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
//在这里会对返回的结果做个简单的判断,因为原始类型不能为null,这里会判断方法的返回类型是不是原始类型,当前的返回值是不是null,如果两者都是就抛出异常
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
下面我们看看this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);这句代码具体的执行情况
//这个方法是在AdvisedSupport类中
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, @Nullable Class<?> targetClass) {
//这里会对方法的拦截器列表做个缓存
//当前这里缓存中是没有的,所以会走到if分支中
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
//我们进到这个分支中看看
//这里的this.advisorChainFactory是一个成员变量,在声明的时候就初始化了,之后没有调用set方法重新赋值 //advisorChainFactory = new DefaultAdvisorChainFactory();
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
//获取到对应的拦截器列表后,加到缓存中,下次就可以直接获取到
this.methodCache.put(cacheKey, cached);
}
return cached;
}
看看this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(this, method, targetClass)这句的执行过程
//这个方法是DefaultAdvisorChainFactory
@Override
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, @Nullable Class<?> targetClass) {
// This is somewhat tricky... We have to process introductions first,
// but we need to preserve order in the ultimate list.
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//这里的advisors数组中只有一个对象,BeanFactoryTransactionAttributeSourceAdvisor。这个类上篇文章中也就有讲,这里也就不再说了
Advisor[] advisors = config.getAdvisors();
List<Object> interceptorList = new ArrayList<>(advisors.length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
Boolean hasIntroductions = null;
for (Advisor advisor : advisors) {
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
......//这里都是判断方法是否和advisors是否匹配,和上篇文章中的匹配步骤基本也是一致的,这里也就略过了
if (match) {
//如果能够匹配,就会从advisor中获取方法的拦截器列表,加到list中最终返回
//getInterceptors这个方法也比较简单,就是直接通过advisor.getAdvice()获取拦截器
//不过这个方法里面有一些其他的知识点,所以我们还是进去一起看看
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
//后面的代码基本都走不到,这里就直接略过了
......
return interceptorList;
}
//DefaultAdvisorAdapterRegistry中的方法
@Override
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<>(3);
//这里的advice就是TransactionInterceptor了,上篇文章也讲过了
//Advice对应我们中文的术语好像叫通知,感觉好别扭