@Transactional内部的秘密

我们都知道Transactional是通过aop实现的,这里介绍一下更底层的代码原理,我们直接从AnnotationAwareAspectJAutoProxyCreator这个类开始分析, 也就是说当一个服务类的某个方法带上了@Transactional时,这个类是如何帮助生成代理类的.

项目启动阶段

AnnotationAwareAspectJAutoProxyCreator 的继承图如下图所示,我们可以看到它本质是一个BeanPostProcessor,BeanPostProcessor 会在对象初始化的前后,对对象进行修改.

在这里插入图片描述

postProcessAfterInitialization方法 开始对 原生的对象 生成代理对象.

/**
   	 * Create a proxy with the configured interceptors if the bean is
   	 * identified as one to proxy by the subclass.
   	 * @see #getAdvicesAndAdvisorsForBean
   	 */
   	@Override
   	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   		if (bean != null) {
   			Object cacheKey = getCacheKey(bean.getClass(), beanName);
   			if (this.earlyProxyReferences.remove(cacheKey) != bean) {
   				return wrapIfNecessary(bean, beanName, cacheKey);
   			}
   		}
   		return bean;
   	}

那AnnotationAwareAspectJAutoProxyCreator为啥会认为某个服务类需要针对Transactional进行包装呢?我们开始走读代码, 在 wrapIfNecessary 方法里, 会先找 适合的 Advisors 给当前bean, 在spring aop中,你可以将advisor理解为aop所需信息的封装,切面中通常有2个关键信息:

  • 需要增强的目标方法列表,这个通过切入点(Pointcut)来指定
  • 需要在目标方法中增强的逻辑,这个通过(Advice)通知来指定

wrapIfNecessary 内部走到 createProxy 方法, ProxyFactory 一看也知道是工厂类, 一个是cglib,一个是jdk动态代理,因为我们这个是class非接口,所以走的是cglib的工厂. 我们可以注意到其中 addAdvisors 方法把 Advisors 也带上了,换句话说, 增强的逻辑不能丢嘛.

protected Object createProxy(
   			Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
   
   		if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
   			AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   		}
   
   		ProxyFactory proxyFactory = new ProxyFactory();
   		proxyFactory.copyFrom(this);
   
   		if (!proxyFactory.isProxyTargetClass()) {
   			if (shouldProxyTargetClass(beanClass, beanName)) {
   				proxyFactory.setProxyTargetClass(true);
   			}
   			else {
   				evaluateProxyInterfaces(beanClass, proxyFactory);
   			}
   		}
   
   		Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   		proxyFactory.addAdvisors(advisors);
   		proxyFactory.setTargetSource(targetSource);
   		customizeProxyFactory(proxyFactory);
   
   		proxyFactory.setFrozen(this.freezeProxy);
   		if (advisorsPreFiltered()) {
   			proxyFactory.setPreFiltered(true);
   		}
   
   		return proxyFactory.getProxy(getProxyClassLoader());
   	}

当走进 CglibAopProxy 的 proxyFactory.getProxy 方法时, 有一个callbacks数组很重要,见下图,因为cglib生成的代理类里,每个方法都回调callbacks里对象的方法. 并且记住callbacks数组的第一个对象 DynamicAdvisedInterceptor, 回调的时候就是回调这个对象的方法.

@Override
	public Object getProxy(ClassLoader classLoader) {
		if (logger.isDebugEnabled()) {
			logger.debug("Creating CGLIB proxy: target source is " + this.advised.getTargetSource());
		}

		try {
			Class<?> rootClass = this.advised.getTargetClass();
			Assert.state(rootClass != null, "Target class must be available for creating a CGLIB proxy");

			Class<?> proxySuperClass = rootClass;
			if (ClassUtils.isCglibProxyClass(rootClass)) {
				proxySuperClass = rootClass.getSuperclass();
				Class<?>[] additionalInterfaces = rootClass.getInterfaces();
				for (Class<?> additionalInterface : additionalInterfaces) {
					this.advised.addInterface(additionalInterface);
				}
			}

			// Validate the class, writing log messages as necessary.
			validateClassIfNecessary(proxySuperClass, classLoader);

			// Configure CGLIB Enhancer...
			Enhancer enhancer = createEnhancer();
			if (classLoader != null) {
				enhancer.setClassLoader(classLoader);
				if (classLoader instanceof SmartClassLoader &&
						((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
					enhancer.setUseCache(false);
				}
			}
			enhancer.setSuperclass(proxySuperClass);
			enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));

			// callbacks 存了代理类的回调逻辑
			Callback[] callbacks = getCallbacks(rootClass);
			Class<?>[] types = new Class<?>[callbacks.length];
			for (int x = 0; x < types.length; x++) {
				types[x] = callbacks[x].getClass();
			}
			// fixedInterceptorMap only populated at this point, after getCallbacks call above
			enhancer.setCallbackFilter(new ProxyCallbackFilter(
					this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
			enhancer.setCallbackTypes(types);

			// Generate the proxy class and create a proxy instance.
			return createProxyClassAndInstance(enhancer, callbacks);
		}
		catch (CodeGenerationException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (IllegalArgumentException ex) {
			throw new AopConfigException("Could not generate CGLIB subclass of " + this.advised.getTargetClass() +
					": Common causes of this problem include using a final class or a non-visible class",
					ex);
		}
		catch (Throwable ex) {
			// TargetSource.getTarget() failed
			throw new AopConfigException("Unexpected AOP exception", ex);
		}
	}

项目运行阶段

到目前为止, 项目启动阶段 代码就分析完毕了,因为后续的逻辑需要debug代码运行阶段,才能看出端倪. 我们先看下生成的代理类是长啥样的.

顺便说一句, 下面代码加在spring的启动类可以在本地生成 经过cglib 代理过的类.

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\git");

我做了代码节选, 这个save方法就是经过@Transactional修饰过的方法. var10000 是 this.CGLIB C A L L B A C K 0 赋 值 而 来 , t h i s . C G L I B CALLBACK_0 赋值而来, this.CGLIB CALLBACK0,this.CGLIBCALLBACK_0 是由 Callback 数组的第一项赋值, 根据前面的分析, 我们可以推出 var10000 就是 DynamicAdvisedInterceptor.

public void setCallbacks(Callback[] var1) {
        try {
            this.CGLIB$CALLBACK_0 = (MethodInterceptor)var1[0];
            this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];
            this.CGLIB$CALLBACK_2 = (NoOp)var1[2];
            this.CGLIB$CALLBACK_3 = (Dispatcher)var1[3];
            this.CGLIB$CALLBACK_4 = (Dispatcher)var1[4];
            this.CGLIB$CALLBACK_5 = (MethodInterceptor)var1[5];
            this.CGLIB$CALLBACK_6 = (MethodInterceptor)var1[6];
        } catch (Error | RuntimeException var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

public final void save(AlarmInfoMysqlSave var1) {
        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$save$1$Method, new Object[]{var1}, CGLIB$save$1$Proxy);
            } else {
                super.save(var1);
            }
        } catch (Error | RuntimeException var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

DynamicAdvisedInterceptor 注释显示是一个通用的AOP回调类,而且类如其名,它 可以动态的匹配合适的代理逻辑,为什么@Transactional 修饰的方法会自动带上 事务逻辑,马上就可以浮出水面。

接下来的代码debug在 程序的运行阶段. 上文知道, 我们走save方法,其实进了DynamicAdvisedInterceptor 对象的intercept方法,我们就从这里开始debug.

这里是一个责任链模式, getInterceptorsAndDynamicInterceptionAdvice 方法会遍历 Advisors, 拿到MethodInterceptor,然后可能会依次执行 ,为什么是可能? 因为 只有对符合匹配的method才能用这个aop策略, 就比如 带有@Transactional注解的method才能匹配事务逻辑。

@Override
		public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
			Object oldProxy = null;
			boolean setProxyContext = false;
			Class<?> targetClass = null;
			Object target = null;
			try {
				if (this.advised.exposeProxy) {
					// Make invocation available if necessary.
					oldProxy = AopContext.setCurrentProxy(proxy);
					setProxyContext = true;
				}
				// May be null. Get as late as possible to minimize the time we
				// "own" the target, in case it comes from a pool...
				target = getTarget();
				if (target != null) {
					targetClass = target.getClass();
				}
				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...
					retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
				}
				retVal = processReturnType(proxy, target, method, retVal);
				return retVal;
			}
			finally {
				if (target != null) {
					releaseTarget(target);
				}
				if (setProxyContext) {
					// Restore old proxy.
					AopContext.setCurrentProxy(oldProxy);
				}
			}
		}

getInterceptorsAndDynamicInterceptionAdvice方法内部 会调用 getInterceptorsAndDynamicInterceptionAdvice方法(Spring的方法名,类名都实在太长了), 大概流程就是遍历 Advisors, 拿到MethodInterceptor. MethodMatchers.matches会做具体的匹配逻辑

@Override
	public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
			Advised config, Method method, Class<?> targetClass) {

		// This is somewhat tricky... We have to process introductions first,
		// but we need to preserve order in the ultimate list.
		List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
		Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
		boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
		AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();

		for (Advisor advisor : config.getAdvisors()) {
			if (advisor instanceof PointcutAdvisor) {
				// Add it conditionally.
				PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
				if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
					MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
					if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
						MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
						if (mm.isRuntime()) {
							// Creating a new object instance in the getInterceptors() method
							// isn't a problem as we normally cache created chains.
							for (MethodInterceptor interceptor : interceptors) {
								interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
							}
						}
						else {
							interceptorList.addAll(Arrays.asList(interceptors));
						}
					}
				}
			}
			else if (advisor instanceof IntroductionAdvisor) {
				IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
				if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
					Interceptor[] interceptors = registry.getInterceptors(advisor);
					interceptorList.addAll(Arrays.asList(interceptors));
				}
			}
			else {
				Interceptor[] interceptors = registry.getInterceptors(advisor);
				interceptorList.addAll(Arrays.asList(interceptors));
			}
		}

		return interceptorList;
	}

深入 MethodMatchers.matches 方法,你就能看见熟悉的Transactional.class,终于找到aop逻辑 匹配 method的代码了. 如何找到合适的method逻辑也焕然开朗.

public class SpringTransactionAnnotationParser implements TransactionAnnotationParser, Serializable {

	@Override
	public TransactionAttribute parseTransactionAnnotation(AnnotatedElement element) {
		AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(
				element, Transactional.class);
		if (attributes != null) {
			return parseTransactionAnnotation(attributes);
		}
		else {
			return null;
		}
	}


现在只剩下最后一步 执行aop逻辑了. 前面说了, DynamicAdvisedInterceptor会依次执行 MethodInterceptor, 我们重新看 DynamicAdvisedInterceptor 的 intercept 方法

proceed 方法就是执行具体逻辑了,

retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();

往下跟, 就是 TransactionInterceptor 的invoke 执行逻辑

	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

这里就是 具体的加强逻辑,这是一个环绕通知, 先把事务打开

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;
			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;
			}
		}
	}

然后proceedWithInvocation方法会重新进入 invocation.proceed() ,为啥会进入这里,因为利用Lambda表达式策略模式,指定规则,看下图

	@Override
	public Object invoke(final MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}

然后 这一段(invokeJoinpoint方法)会进入到业务代码,业务代码走完,继续执行 关闭事务等操作,这一段 事务之旅就算完结!

@Override
	public Object proceed() throws Throwable {
		//	We start with an index of -1 and increment early.
		if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
			return invokeJoinpoint();
		}

        ······
	}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值