美文网首页深度解析Spring5源码
44--Spring @Transactional声明式事物(一

44--Spring @Transactional声明式事物(一

作者: 闲来也无事 | 来源:发表于2018-12-27 09:56 被阅读83次
    1.引

    上一节已经分析了基于@Transactional注解的声明式事物事物标签提取,接下来我们就接下来我们就要分析Spring事物的实现过程了,因为这里会涉及到事物传播特性、事物嵌套调用等等很多复杂的内容,所以第一个分析,还是以最简单的形式去分析,及单个service下的单个方法调用。业务方法摘要如下,在业务方法上配置了Transactional注解,并将事物传播特性定义为REQUIRED。在分析完这个最简单的例子之后,再去分析比较复杂的事物调用过程。。。

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete() throws RuntimeException {
        System.out.println("==调用AccountService的delete方法\n");
        jdbcTemplate.update(insert_sql);
    
        throw new RuntimeException("==AccountService的delete方法手动抛出异常");
    }
    
    2.拦截器链调用回顾

    拦截器链调用入口:

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation;
        Object oldProxy = null;
        boolean setProxyContext = false;
    
        TargetSource targetSource = this.advised.targetSource;
        Object target = null;
    
        try {
            // 1、处理equals方法,如果接口中没有定义equals而在实现类中覆盖了equals方法,那么该equals方法不会被增强
            if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
                // The target does not implement the equals(Object) method itself.
                return equals(args[0]);
            }
            // 2、处理hashCode方法,如果接口中没有定义hashCode而在实现类中覆盖了hashCode方法,那么该hashCode方法不会被增强
            else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
                // The target does not implement the hashCode() method itself.
                return hashCode();
            }
            // 3、如果目标对象是DecoratingProxy类型,则返回目标对象的最终对象类型
            // DecoratingProxy接口只有一个getDecoratedClass方法,用于返回目标对象的最终对象类型
            else if (method.getDeclaringClass() == DecoratingProxy.class) {
                // There is only getDecoratedClass() declared -> dispatch to proxy config.
                return AopProxyUtils.ultimateTargetClass(this.advised);
            }
            // 4、如果目标对象是Advice类型,则直接使用反射进行调用
            // opaque-->标记是否需要阻止通过该配置创建的代理对象转换为Advised类型,默认值为false,表示代理对象可以被转换为Advised类型
            // method.getDeclaringClass().isInterface()-->目标对象是接口
            // method.getDeclaringClass().isAssignableFrom(Advised.class)-->
            // 是用来判断一个类Class1和另一个类Class2是否相同或者Class1类是不是Class2的父类。例如:Class1.isAssignableFrom(Class2)
            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;
    
            // 5、解决目标对象内部自我调用无法实施切面增强,在这里暴露代理
            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);
    
            // Get the interception chain for this method.
            // 6、获取当前方法的拦截器链,并执行调用
            List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    
            // 检测是否拦截器链是否为空,如果拦截器链为空,那么直接通过反射调用目标对象的方法,避免创建MethodInvocation
            // 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 {
                // 创建MethodInvocation对象并调用proceed方法,拦截器链被封装到了invocation中
                // 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();
            }
    
            // 7、返回结果
            // 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);
            }
        }
    }
    

    真正执行拦截器链调用

    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;
            Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());
            // 匹配成功则执行
            if (dm.methodMatcher.matches(this.method, 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.
            // System.out.println(interceptorOrInterceptionAdvice.getClass());
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
    

    以上的代码之前都已经分析过,像其中的拦截器链获取等,就不再详细分析了,当代码执行到这里的proceed方法里,如果我们没有配置其他的AOP增强,那么第一个被执行的拦截器就是TransactionInterceptor(事物拦截器)

    3.TransactionInterceptor实现事物管理过程简析
    public Object invoke(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, invocation::proceed);
    }
    
    protected Object invokeWithinTransaction(Method method,
                                                 @Nullable Class<?> targetClass,
                                                 final InvocationCallback invocation) throws Throwable {
        // 1.准备工作
        // If the transaction attribute is null, the method is non-transactional.
        TransactionAttributeSource tas = getTransactionAttributeSource();
        // 获取事物属性
        final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
        // 获取事物管理器
        final PlatformTransactionManager tm = determineTransactionManager(txAttr);
        // 获取目标类全限定类名+连接点方法名 例如:com.lyc.cn.v2.day09.AccountServiceImpl.save
        final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
    
        // 2.处理声明式事物
        if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
            // Standard transaction demarcation with getTransaction and commit/rollback calls.
            // 2.2 创建事物
            TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
            System.out.println("==创建了名为:["+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.
                // 2.3 继续调用方法拦截器链,这里一般将会调用目标类的方法,如:com.lyc.cn.v2.day09.AccountServiceImpl.save方法
                retVal = invocation.proceedWithInvocation();
            } catch (Throwable ex) {
                // target invocation exception
                // 2.4 如果目标类方法抛出异常,则在此处理,例如:事物回滚
                completeTransactionAfterThrowing(txInfo, ex);
                throw ex;
            } finally {
                // 2.5 清除上一步创建的事物信息
                cleanupTransactionInfo(txInfo);
            }
            // 2.6 调用成功完成后执行,但不是在异常被处理后执行。如果我们不创建事务,就什么也不做。
            commitTransactionAfterReturning(txInfo);
            return retVal;
        }
    
        // 3.处理编程式事物
        else {
            final ThrowableHolder throwableHolder = new ThrowableHolder();
            // It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
            try {
                Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, 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;
            }
        }
    }
    

    这里对声明式事物和编程式事物分别做了不同的处理,我们主要看声明式事物的实现过程,第一步的准备工作比较简单,第二步是整个事物的核心所在。

    • 创建事物
    • 继续调用方法拦截器链,这里一般将会调用目标类的方法,如:com.lyc.cn.v2.day09.AccountServiceImpl.save方法
    • 如果目标类方法抛出异常,则在此处理,例如:事物回滚
    • 清除上一步创建的事物信息
    • 调用成功完成后执行commitTransactionAfterReturning方法,但不是在异常被处理后执行。如果我们不创建事务,就什么也不做。

    分析到这里,我们也仅仅是得到了Spring事物管理的一些步骤,继续分析,接下来就是Spring创建事物的过程了。这一部分的内容太多了,还是分篇幅介绍吧。。。

    相关文章

      网友评论

        本文标题:44--Spring @Transactional声明式事物(一

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