wbo112

springboot 事务执行全流程分析

2021-10-24 12:13  wang03  阅读(0)  评论(0编辑  收藏  举报

springboot 事务执行全流程分析

在上篇文章springboot 事务创建流程源码分析中主要讲了springboot事务创建的过程,本次我们来看看事务具体执行的过程。

这里关于几个名称提前先达成一致:

  1. com.springboot.transaction.service.impl.UserServiceImpl这个类我们称它为原始类,它的对象我们称原始对象

  2. 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对应我们中文的术语好像叫通知,感觉好别扭            
                

分类:

技术点:

java

相关文章:

猜你喜欢