美文网首页
Spring事务杂记

Spring事务杂记

作者: 未城居士 | 来源:发表于2019-07-17 10:38 被阅读0次

    org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction

    public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
           Object transaction = doGetTransaction();
    
           // Cache debug flag to avoid repeated checks.
           boolean debugEnabled = logger.isDebugEnabled();
    
           if (definition == null) {
               // Use defaults if no transaction definition given.
               definition = new DefaultTransactionDefinition();
           }
    
           if (isExistingTransaction(transaction)) {
               // Existing transaction found -> check propagation behavior to find out how to behave.
               return handleExistingTransaction(definition, transaction, debugEnabled);
           }
    
           // Check definition settings for new transaction.
           if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
               throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
           }
    
           // No existing transaction found -> check propagation behavior to find out how to proceed.
           if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
               throw new IllegalTransactionStateException(
                       "No existing transaction found for transaction marked with propagation 'mandatory'");
           }
           else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
                   definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
                   definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
               SuspendedResourcesHolder suspendedResources = suspend(null);
               if (debugEnabled) {
                   logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
               }
               try {
                   boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
                   DefaultTransactionStatus status = newTransactionStatus(
                           definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
                   doBegin(transaction, definition);
                   prepareSynchronization(status, definition);
                   return status;
               }
               catch (RuntimeException ex) {
                   resume(null, suspendedResources);
                   throw ex;
               }
               catch (Error err) {
                   resume(null, suspendedResources);
                   throw err;
               }
           }
           else {
               // Create "empty" transaction: no actual transaction, but potentially synchronization.
               if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
                   logger.warn("Custom isolation level specified but no actual transaction initiated; " +
                           "isolation level will effectively be ignored: " + definition);
               }
               boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
               return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
           }
       }
    

    属性处理

        protected TransactionInfo prepareTransactionInfo(PlatformTransactionManager tm,
                TransactionAttribute txAttr, String joinpointIdentification, TransactionStatus status) {
    
            TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);
            if (txAttr != null) {
                // We need a transaction for this method...
                if (logger.isTraceEnabled()) {
                    logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
                }
                // The transaction manager will flag an error if an incompatible tx already exists.
                txInfo.newTransactionStatus(status);
            }
            else {
                // The TransactionInfo.hasTransaction() method will return false. We created it only
                // to preserve the integrity of the ThreadLocal stack maintained in this class.
                if (logger.isTraceEnabled())
                    logger.trace("Don't need to create transaction for [" + joinpointIdentification +
                            "]: This method isn't transactional.");
            }
    
            // We always bind the TransactionInfo to the thread, even if we didn't create
            // a new transaction here. This guarantees that the TransactionInfo stack
            // will be managed correctly even if no transaction was created by this aspect.
            txInfo.bindToThread();
            return txInfo;
        }
    
    image.png image.png
    protected final class TransactionInfo {
    
            private final PlatformTransactionManager transactionManager;
    
            private final TransactionAttribute transactionAttribute;
    
            private final String joinpointIdentification;
    
            private TransactionStatus transactionStatus;
    
            private TransactionInfo oldTransactionInfo;
            
    }
    

    org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

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

    这是切面AOP的包
    org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

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

    上面的反射包会走到下面的类,

        /**
         * Implementation of AOP Alliance MethodInvocation used by this AOP proxy.
         */
        private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
    
            private final MethodProxy methodProxy;
    
            private final boolean publicMethod;
    
            public CglibMethodInvocation(Object proxy, Object target, Method method, Object[] arguments,
                    Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers, MethodProxy methodProxy) {
    
                super(proxy, target, method, arguments, targetClass, interceptorsAndDynamicMethodMatchers);
                this.methodProxy = methodProxy;
                this.publicMethod = Modifier.isPublic(method.getModifiers());
            }
    
            /**
             * Gives a marginal performance improvement versus using reflection to
             * invoke the target when invoking public methods.
             */
            @Override
            protected Object invokeJoinpoint() throws Throwable {
                if (this.publicMethod) {
                    return this.methodProxy.invoke(this.target, this.arguments);
                }
                else {
                    return super.invokeJoinpoint();
                }
            }
        }
    

    反射invoke后会走到真正的方法
    org.springframework.cglib.proxy.MethodProxy#invoke

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodInvocation invocation;
            Object oldProxy = null;
            boolean setProxyContext = false;
    
            TargetSource targetSource = this.advised.targetSource;
            Class<?> targetClass = null;
            Object target = null;
    
            try {
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    // The target does not implement the equals(Object) method itself.
                    return equals(args[0]);
                }
                else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    // The target does not implement the hashCode() method itself.
                    return hashCode();
                }
                else if (method.getDeclaringClass() == DecoratingProxy.class) {
                    // There is only getDecoratedClass() declared -> dispatch to proxy config.
                    return AopProxyUtils.ultimateTargetClass(this.advised);
                }
                else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    // Service invocations on ProxyConfig with the proxy config...
                    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                }
    
                Object retVal;
    
                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 = targetSource.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
    
                // Get the interception chain for this method.
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
                // Check whether we have any advice. If we don't, we can fallback on direct
                // reflective invocation of the target, and avoid creating a MethodInvocation.
                if (chain.isEmpty()) {
                    // 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    // Proceed to the joinpoint through the interceptor chain.
                    retVal = invocation.proceed();
                }
    
                // Massage return value if necessary.
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target &&
                        returnType != Object.class && returnType.isInstance(proxy) &&
                        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    // Special case: it returned "this" and the return type of the method
                    // is type-compatible. Note that we can't help if the target sets
                    // a reference to itself in another returned object.
                    retVal = proxy;
                }
                else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                    throw new AopInvocationException(
                            "Null return value from advice does not match primitive return type for: " + method);
                }
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    // Must have come from TargetSource.
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
    

    org.springframework.aop.framework.JdkDynamicAopProxy#invoke

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            MethodInvocation invocation;
            Object oldProxy = null;
            boolean setProxyContext = false;
    
            TargetSource targetSource = this.advised.targetSource;
            Class<?> targetClass = null;
            Object target = null;
    
            try {
                if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                    // The target does not implement the equals(Object) method itself.
                    return equals(args[0]);
                }
                else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                    // The target does not implement the hashCode() method itself.
                    return hashCode();
                }
                else if (method.getDeclaringClass() == DecoratingProxy.class) {
                    // There is only getDecoratedClass() declared -> dispatch to proxy config.
                    return AopProxyUtils.ultimateTargetClass(this.advised);
                }
                else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
                        method.getDeclaringClass().isAssignableFrom(Advised.class)) {
                    // Service invocations on ProxyConfig with the proxy config...
                    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
                }
    
                Object retVal;
    
                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 = targetSource.getTarget();
                if (target != null) {
                    targetClass = target.getClass();
                }
    
                // Get the interception chain for this method.
                List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
                // Check whether we have any advice. If we don't, we can fallback on direct
                // reflective invocation of the target, and avoid creating a MethodInvocation.
                if (chain.isEmpty()) {
                    // 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 = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
                }
                else {
                    // We need to create a method invocation...
                    invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
                    // Proceed to the joinpoint through the interceptor chain.
                    retVal = invocation.proceed();
                }
    
                // Massage return value if necessary.
                Class<?> returnType = method.getReturnType();
                if (retVal != null && retVal == target &&
                        returnType != Object.class && returnType.isInstance(proxy) &&
                        !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
                    // Special case: it returned "this" and the return type of the method
                    // is type-compatible. Note that we can't help if the target sets
                    // a reference to itself in another returned object.
                    retVal = proxy;
                }
                else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
                    throw new AopInvocationException(
                            "Null return value from advice does not match primitive return type for: " + method);
                }
                return retVal;
            }
            finally {
                if (target != null && !targetSource.isStatic()) {
                    // Must have come from TargetSource.
                    targetSource.releaseTarget(target);
                }
                if (setProxyContext) {
                    // Restore old proxy.
                    AopContext.setCurrentProxy(oldProxy);
                }
            }
        }
    

    获取目标类
    TargetSource targetSource = this.advised.targetSource;


    image.png

    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    通过链,创建invocation
    执行方法
    retVal = invocation.proceed();

    会走到
    org.springframework.transaction.interceptor.TransactionInterceptor#invoke

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

    很明显,有进行事务处理的逻辑

    TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

    image.png

    调用路线:
    org.springframework.aop.framework.CglibAopProxy.DynamicAdvisedInterceptor#intercept
    org.springframework.aop.framework.CglibAopProxy.CglibMethodInvocation
    org.springframework.aop.framework.CglibAopProxy#processReturnType

    org.springframework.aop.framework.JdkDynamicAopProxy#invoke

    chain

    org.springframework.aop.framework.ReflectiveMethodInvocation#proceed
    org.springframework.transaction.interceptor.TransactionInterceptor#invoke
    org.springframework.transaction.interceptor.TransactionAspectSupport#invokeWithinTransaction

    • org.springframework.transaction.interceptor.TransactionAspectSupport#createTransactionIfNecessary
    • org.springframework.transaction.support.AbstractPlatformTransactionManager#getTransaction
    • org.springframework.transaction.support.AbstractPlatformTransactionManager#handleExistingTransaction
    • org.springframework.transaction.interceptor.TransactionAspectSupport#prepareTransactionInfo
      回调
      org.springframework.aop.framework.ReflectiveMethodInvocation#proceed

    org.springframework.aop.framework.ReflectiveMethodInvocation#invokeJoinpoint
    org.springframework.aop.support.AopUtils#invokeJoinpointUsingReflection
    java.lang.reflect.Method#invoke
    com.gongdao.middleware.api.impl.LocalServiceImpl#newTransitionMethod
    org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo
    org.springframework.transaction.interceptor.TransactionAspectSupport#cleanupTransactionInfo
    org.springframework.transaction.interceptor.TransactionAspectSupport.TransactionInfo#restoreThreadLocalStatus
    org.springframework.transaction.interceptor.TransactionAspectSupport#commitTransactionAfterReturning
    org.springframework.transaction.support.AbstractPlatformTransactionManager#commit
    org.springframework.transaction.support.AbstractPlatformTransactionManager#processCommit
    com.gongdao.middleware.db.GongDaoDataSourceTransactionManager#doCommit
    org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCommit
    org.springframework.transaction.support.AbstractPlatformTransactionManager#triggerAfterCompletion
    ......
    org.springframework.transaction.support.AbstractPlatformTransactionManager#cleanupAfterCompletion
    com.gongdao.middleware.db.GongDaoDataSourceTransactionManager#doCleanupAfterCompletion

    image.png

    相关文章

      网友评论

          本文标题:Spring事务杂记

          本文链接:https://www.haomeiwen.com/subject/opoflctx.html