Spring Aop事务分析

  • 事务方法通过cglib生成
  • 执行方法的时候,
List 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();
                }
 
 

chain里有4个interceptor,分别是

  1. ExposeInvocationInterceptor:用于设置和恢复原来的MethodInvocation。
  2. MethodBeforeAdviceInterceptor:一般用于设置数据源(order在transactionManager前面)
  3. AfterReturningAdviceInterceptor:一般用于clear数据源
  4. TransactionInterceptor:执行事务

3是在4之后执行的,看代码

@Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        Object retVal = mi.proceed();
        this.advice.afterReturning(retVal, mi.getMethod(), mi.getArguments(), mi.getThis());
        return retVal;
    }

mi.proceed()是执行后面的代码,是个链式执行方式,和filter原理一样。

@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();
        }

        Object interceptorOrInterceptionAdvice =
                this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            // Evaluate dynamic method matcher here: static part will already have
            // been evaluated and found to match.
            InterceptorAndDynamicMethodMatcher dm =
                    (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                // Dynamic matching failed.
                // Skip this interceptor and invoke the next in the chain.
                return proceed();
            }
        }
        else {
            // It's an interceptor, so we just invoke it: The pointcut will have
            // been evaluated statically before this object was constructed.
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }

当整个链执行完后,进入invokeJoinpoint(),这里执行你的业务方法。

你的业务方法a.method()里如果调用了另一个带事务的方法b.method(),那么b.method()同样是按上面的执行顺序。但是b.method获取TransactionStatus的时候会发现当前线程中有了SessionHolder,因此会被认为不是一个new transaction。而a.method会被认为是new transaction。


在TransactionInterceptor执行中,最后

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

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

commitTransactionAfterReturning()中会判断如果transactionStatus不是new的,不执行doCommit(),因此b.method()执行后不会commit,a.method执行后会commit。


以上是对非跨库事务分析,如果跨库了就变成XA,需要引入2PC等。


如果a.method1()调用了a.method2(),那么a.method2()是不经过cglib生成的,是直接调用,不走事务的4个interceptor。
a.method()调用b.method()才会走4个Interceptor。

a.method()调用b.method(),b.method()调用c.method(),如果他们配置了不同的datasource,只有a上配置的datasource起作用,b和c的不起作用,因为在b,c会判断当前threadlocal中已经有sesessionHolder了,会被认为是一个事务中的。

结论:读写事务要区分,严禁在读服务中调用写服务。


下图:


Spring Aop事务分析_第1张图片
BUCTJYB$VVVE5GCFF8_)(CF.png

类内调用,只有入口方法上的事务才起作用,被调用的方法上的事务配置是不会有影响的。
类外调用,那么调用方法和被调用方法都会被aop代理。

参考https://stackoverflow.com/questions/6222600/transactional-method-calling-another-method-without-transactional-anotation
回答摘录如下:

When you call a method without @Transactional within a transaction block, the parent transaction will continue to the new method. It will use the same connection from the parent method(with @Transactional) and any exception caused in the called method(without @Transactional will cause the transaction to rollback as configured in the transaction definition.

If you call a method with a @Transactional annotation from a method with @Transactional within the same instance, then the called methods transactional behavior will not have any impact on the transaction. But if you call a method with a transaction definition from another method with a transaction definition, and they are in different instances, then the code in the called method will follow the transaction definitions given in the called method.

You can find more details in the section Declarative transaction management of spring transaction documentation.

Spring declarative transaction model uses AOP proxy. so the AOP proxy is responsible for creation of the transactions. The AOP proxy will be active only if the methods with in the instance are called from out side the instance.


疑问:cglib会对每个方法都进行“代理”的,为什么类内方法调用不经过那些Interceptor呢?
在类内调用时,调用called method的对象是FastClassBySpringCGLIB,并不是EnhancerBySpringCGLIB,FastClass并没有对类增强,仅仅是加快反射调用速度,具体分析见https://dzone.com/articles/cglib-missing-manual。

你可能感兴趣的:(Spring Aop事务分析)