乐趣区

Spring事务源码解析二获取增强

在上一篇文章 @EnableTransactionManagement 注解解析中,我们搭建了源码阅读的环境,以及解析了开启 Spring 事务功能的注解 @EnableTransactionManagement 的实现逻辑

在进行接下来的源码解析之前我想大家应该知道,当我们使用传统的 jdbc 应用事务的时候是不是做了如下操作:

  1. 开启事务
  2. save、update、delete 等操作
  3. 出现异常进行回滚
  4. 正常情况提交事务

而在 Spring 中我们好像只需要关心第三步,也就是我们的业务,而其他的操作都不需要关心。那么我想你应该猜到了 Spring 是如何实现的呢?
答案就是基于 @Transactional 注解的 SpringAOP 实现,在接着往下阅读本篇文章的时候希望您对于 SpringAOP 的源码有一定的了解,如果不了解可以参考如下文章:

  1. 基于注解的 SpringAOP 源码解析(一)
  2. 基于注解的 SpringAOP 源码解析(二)
  3. 基于注解的 SpringAOP 源码解析(三)
获取增强

在阅读完 AOP 的原理之后,我们知道,当一个 bean 实例化之后会尝试获取所有适用于此 Bean 的增强。而在上篇文章中,我们已经发现了,@EnableTransactionManagement注解会往 Spring 中注入一个增强 BeanFactoryTransactionAttributeSourceAdvisor。经过一番代码调用以后,会进入这么一个方法,这里的第一个入参就是BeanFactoryTransactionAttributeSourceAdvisor 增强

    public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {if (advisor instanceof IntroductionAdvisor) {return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
        }
        else if (advisor instanceof PointcutAdvisor) {PointcutAdvisor pca = (PointcutAdvisor) advisor;
            return canApply(pca.getPointcut(), targetClass, hasIntroductions);
        }
        else {return true;}
    }
 public static boolean canApply(Pointcut pc, Class<?> targetClass, boolean hasIntroductions) {Assert.notNull(pc, "Pointcut must not be null");
        if (!pc.getClassFilter().matches(targetClass)) {return false;}
        MethodMatcher methodMatcher = pc.getMethodMatcher();
        if (methodMatcher == MethodMatcher.TRUE) {return true;}

        IntroductionAwareMethodMatcher introductionAwareMethodMatcher = null;
        if (methodMatcher instanceof IntroductionAwareMethodMatcher) {introductionAwareMethodMatcher = (IntroductionAwareMethodMatcher) methodMatcher;
        }

        Set<Class<?>> classes = new LinkedHashSet<>(ClassUtils.getAllInterfacesForClassAsSet(targetClass));
        classes.add(targetClass);
        for (Class<?> clazz : classes) {
          // 获取当前类的所有方法
            Method[] methods = ReflectionUtils.getAllDeclaredMethods(clazz);
            for (Method method : methods) {
                if ((introductionAwareMethodMatcher != null &&
                        introductionAwareMethodMatcher.matches(method, targetClass, hasIntroductions)) ||
                        methodMatcher.matches(method, targetClass)) {return true;}
            }
        }

        return false;
    }

到这里的时候就进入事务相关的类TransactionAttributeSourcePointcut,看名字就能知道,这是个切点类. 那么接下来的逻辑应该可以想象到,无非就是判断是否是个事务方法

public boolean matches(Method method, @Nullable Class<?> targetClass) {if (targetClass != null && TransactionalProxy.class.isAssignableFrom(targetClass)) {return false;}
        TransactionAttributeSource tas = getTransactionAttributeSource();
        return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
    }
    

如果是事务方法则继续往下走

public TransactionAttribute getTransactionAttribute(Method method, 
      @Nullable Class<?> targetClass) {
    // 如果当前方法是 Object 类中的方法,则直接返回
    if (method.getDeclaringClass() == Object.class) {return null;}

    // 获取当前方法缓存使用的 key
    Object cacheKey = getCacheKey(method, targetClass);
    Object cached = this.attributeCache.get(cacheKey);
    // 从缓存中获取当前方法解析的事务属性,如果解析过,则将解析结果返回
    if (cached != null) {if (cached == NULL_TRANSACTION_ATTRIBUTE) {return null;} else {return (TransactionAttribute) cached;
        }
    } else {
        // 解析当前方法的事务属性,这里很重要,下面说
        TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
        if (txAttr == null) {
            // 如果当前方法上没有事务属性,则缓存一个表示空事务属性的对象
            this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
        } else {
            // 获取方法的签名
            String methodIdentification = 
                ClassUtils.getQualifiedMethodName(method, targetClass);
            // 如果生成的事务属性是 DefaultTransactionAttribute 类型的,则将方法签名设置到其 descriptor 属性中
            if (txAttr instanceof DefaultTransactionAttribute) {((DefaultTransactionAttribute) txAttr)
                    .setDescriptor(methodIdentification);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Adding transactional method'" + methodIdentification 
                             + "'with attribute:" + txAttr);
            }
            // 缓存当前方法的解析结果
            this.attributeCache.put(cacheKey, txAttr);
        }
        return txAttr;
    }
}

接着看一下方法的事务属性是如何解析的

protected TransactionAttribute computeTransactionAttribute(Method method, 
       @Nullable Class<?> targetClass) {
    // 如果设置了只对 public 方法进行事务代理,并且当前方法不是 public 的,则返回 null
    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {return null;}

    Class<?> userClass = (targetClass != null ? 
        ClassUtils.getUserClass(targetClass) : null);
    // 获取最为准确的方法,即如果传入的 method 只是一个接口方法,则会去找其实现类的同一方法进行解析
    Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
    // 如果当前方法是一个泛型方法,则会找 Class 文件中实际实现的方法
    specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
    // 解析目标方法,获取其是否存在事务属性,如果存在则直接返回
    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
    if (txAttr != null) {return txAttr;}

    // 解析目标方法所在的类,判断其是否标注有事务属性,如果存在,并且目标方法是用户实现的方法,则直接返回
    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {return txAttr;}

    // 如果通过解析到的方法无法找到事务属性,则判断解析得到的方法与传入的目标方法是否为同一个方法,// 如果不是同一个方法,则尝试对传入的方法及其所在的类进行事务属性解析
    if (specificMethod != method) {
        // 对传入方法解析事务属性,如果存在,则直接返回
        txAttr = findTransactionAttribute(method);
        if (txAttr != null) {return txAttr;}

        // 对传入方法所在类进行事务属性解析,如果存在,则直接返回
        txAttr = findTransactionAttribute(method.getDeclaringClass());
        if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {return txAttr;}
    }

    return null;
}

这里对事务属性的解析主要分为对目标方法进行解析和对传入方法进行解析,接着看 findTransactionAttribute 方法

protected TransactionAttribute findTransactionAttribute(Method method) {return determineTransactionAttribute(method);
    }
    protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {for (TransactionAnnotationParser annotationParser : this.annotationParsers) {TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
            if (attr != null) {return attr;}
        }
        return null;
    }
    public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
        AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(ae, Transactional.class, false, false);
        if (attributes != null) {return parseTransactionAnnotation(attributes);
        }
        else {return null;}
    }
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
    // 判断目标方法上是否存在 @Transactional 注解,如果不存在,则直接返回
    AnnotationAttributes attributes = AnnotatedElementUtils
        .findMergedAnnotationAttributes(ae, Transactional.class, false, false);
    if (attributes != null) {
        // 如果目标方法上存在 @Transactional 注解,则获取注解值,并且封装为 TransactionAttribute 返回
        return parseTransactionAnnotation(attributes);
    } else {return null;}
}

protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
    // 获取注解上的 propagation 值
    Propagation propagation = attributes.getEnum("propagation");
    rbta.setPropagationBehavior(propagation.value());
    // 获取注解上的 isolation 属性值
    Isolation isolation = attributes.getEnum("isolation");
    rbta.setIsolationLevel(isolation.value());
    // 获取注解上的 timeout 属性值
    rbta.setTimeout(attributes.getNumber("timeout").intValue());
    // 获取注解上的 readOnly 属性值
    rbta.setReadOnly(attributes.getBoolean("readOnly"));
    // 获取注解上的 value 属性值
    rbta.setQualifier(attributes.getString("value"));
    ArrayList<RollbackRuleAttribute> rollBackRules = new ArrayList<>();
    // 获取注解上的 rollbackFor 属性列表
    Class<?>[] rbf = attributes.getClassArray("rollbackFor");
    for (Class<?> rbRule : rbf) {RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 获取注解上的 rollbackForClassName 属性列表
    String[] rbfc = attributes.getStringArray("rollbackForClassName");
    for (String rbRule : rbfc) {RollbackRuleAttribute rule = new RollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 获取注解上的 noRollbackFor 属性列表
    Class<?>[] nrbf = attributes.getClassArray("noRollbackFor");
    for (Class<?> rbRule : nrbf) {NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    // 获取注解上的 noRollbackForClassName 属性列表
    String[] nrbfc = attributes.getStringArray("noRollbackForClassName");
    for (String rbRule : nrbfc) {NoRollbackRuleAttribute rule = new NoRollbackRuleAttribute(rbRule);
        rollBackRules.add(rule);
    }
    rbta.getRollbackRules().addAll(rollBackRules);
    return rbta;
}

可以看到这里已经把方法上或者类上的 @Transactional 注解的属性封装成 `
TransactionAttribute 返回了,关于@Transactional` 注解的更多知识可参考我的这篇文章:
Spring@Transactional 注解

退出移动版