Spring源码之事务(二)

本文详细探讨了Spring框架中事务处理的源码实现,从寻找事务类或方法对应的增强器开始,深入匹配增强器的过程,特别是如何提取事务注解信息。通过解析事务属性,理解声明式事务与编程式事务的执行流程,分析了事务的开启、提交、回滚逻辑,以及在AOP代理中如何实现事务管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 前言

接着 Spring源码之事务(一)文章继续

2. 寻找事务类或方法对应的增强器

2.1. getAdvicesAndAdvisorsForBean()

Spring 通过 getAdvicesAndAdvisorsForBean() 获取指定 bean 对应的增强器,不但要找出增强器,而且还需要判断增强器是否满足要求

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
      Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
   
	
	// 寻找所有合适的增强器	
	List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
   	if (advisors.isEmpty()) {
   
      	return DO_NOT_PROXY;
   	}
   	return advisors.toArray();
}

寻找所有合适的增强器(增强器并不一定都适用于当前 bean,要选出满足我们通配符的增强器)

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
   

    // 获取所有的增强
	List<Advisor> candidateAdvisors = findCandidateAdvisors();
    // 寻找所有增强中适用于 bean 的增强并应用
    List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
    // 在advice链的开始添加ExposeInvocationInterceptor
    extendAdvisors(eligibleAdvisors);
    if (!eligibleAdvisors.isEmpty()) {
   
        eligibleAdvisors = sortAdvisors(eligibleAdvisors);
    }
    return eligibleAdvisors;
}

上述方法的任务是:找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性

2.2. 匹配增强器 findAdvisorsThatCanApply()

当找出所有的增强器后,接来的任务就是看这些增强器是否与 bean (比如 ProductInfoServiceImpl)对应的 class 匹配了,当然不只是 classclass 内部的方法如果能够匹配也可以

/*寻找所有增强中适用于目标bean的增强并应用*/
protected List<Advisor> findAdvisorsThatCanApply(
      List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {
   

   /*设置当前要代理的beanName*/
   ProxyCreationContext.setCurrentProxiedBeanName(beanName);
   try {
   
      /*过滤已经得到的advisors*/
      return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
   }
   finally {
   
      /*清除标记*/
      ProxyCreationContext.setCurrentProxiedBeanName(null);
   }
}

/*主要功能是寻找所有增强器中适用于当前class的增强器*/
public static List<Advisor> findAdvisorsThatCanApply(List<Advisor> candidateAdvisors, Class<?> clazz) {
   
    if (candidateAdvisors.isEmpty()) {
   
        return candidateAdvisors;
    }
    // 保存筛选的合适增强器
    List<Advisor> eligibleAdvisors = new ArrayList<>();

    // 首先处理引介增强
    for (Advisor candidate : candidateAdvisors) {
   
        // 核心匹配实现:canApply()
        if (candidate instanceof IntroductionAdvisor && canApply(candidate, clazz)) {
   
            eligibleAdvisors.add(candidate);
        }
    }
    boolean hasIntroductions = !eligibleAdvisors.isEmpty();
    for (Advisor candidate : candidateAdvisors) {
   
        if (candidate instanceof IntroductionAdvisor) {
   
            // 引介增强已经处理
            continue;
        }
        // 如果不是IntroductionAdvisor实例,对于普通的增强,调用canApply()重载方法
        if (canApply(candidate, clazz, hasIntroductions)) {
   
            eligibleAdvisors.add(candidate);
        }
    }
    return eligibleAdvisors;
}

当前我们分析的是对于 ProductInfoServiceImpl 是否适用于此增强方法,那么当前的 advisor 就是之前查找出来的类型为 BeanFactoryTransactionAttributeSourceAdvisorbean 实例。匹配合适的增强器核心步骤就是调用 canApply() 方法

public static boolean canApply(Advisor advisor, Class<?> targetClass) {
   
	return canApply(advisor, targetClass, false);
}

public static boolean canApply(Advisor advisor, Class<?> targetClass, boolean hasIntroductions) {
   
   	// 如果增强是引介增强,那么直接获取切点表达式去匹配targetClass即可
   	if (advisor instanceof IntroductionAdvisor) {
   
      	return ((IntroductionAdvisor) advisor).getClassFilter().matches(targetClass);
   	}
   	// 如果属于PointcutAdvisor,继续调用重载方法
   	else if (advisor instanceof PointcutAdvisor) {
   
      	PointcutAdvisor pca = (PointcutAdvisor) advisor;
      	return canApply(pca.getPointcut(), targetClass, hasIntroductions);
   	}
   	// 其余的默认为符合条件
   	else {
   
      	return true;
   	}
}

通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor 间接实现了 PointcutAdvisor。因此,在 canApply() 函数中的第二个 if 判断时就会通过判断,将 BeanFactoryTransactionAttributeSourceAdvisor 中的 getPointcut() 方法返回值作为参数继续调用 canApply() 方法

那么继续跟踪 canApply() 方法,targetClass 参数为 ProductInfoServiceImpl

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<>();
    // 如果是代理类,则需要返回原始类
    if (!Proxy.isProxyClass(targetClass
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值