Spring源码之事务(二)

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

寻找事务类或方法对应的增强器
跟进 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;
}

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

匹配增强器 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 {
      	// It doesn't have a pointcut so we assume it applies.
      	return true;
   	}
}

通过类的层次结构我们又知道:BeanFactoryTransactionAttributeSourceAdvisor 间接实现了 PointcutAdvisor。因此,在 canApply() 函数中的第二个 if 判断时就会通过判断,将 BeanFactoryTransactionAttributeSourceAdvisor 中的 getPointcut() 方法返回值作为参数继续调用 canApply() 重载方法。getPointcut() 方法返回的是 TransactionAttributeSourcePointcut 类型的实例,可以通过它的 getTransactionAttributeSource() 返回 TransactionAttributeSource 实例。TransactionAttributeSource 实例是我们上一部分注册的四个 bean 之一

public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {

   	@Nullable
   	private TransactionAttributeSource transactionAttributeSource;

   	// 创建BeanFactoryTransactionAttributeSourceAdvisor时,默认就创建出TransactionAttributeSourcePointcut类型的pointcut
   	private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
		@Override
      	@Nullable
      	protected TransactionAttributeSource getTransactionAttributeSource() {
	         return transactionAttributeSource;
      	}
   	};

   	@Override
   	public Pointcut getPointcut() {
      	return this.pointcut;
   	}
}

那么,使用 TransactionAttributeSourcePointcut 类型的实例作为函数参数继续跟踪 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;
    }

    // 然后继续寻找匹配类中哪个方法
    
    // 此时的pc表示TransactionAttributeSourcePointcut,pc.getMethodMatcher()返回的正是自身(this)
    MethodMatcher methodMatcher = pc.getMethodMatcher();
    if (methodMatcher == MethodMatcher.TRUE) {
        // No need to iterate the methods if we're matching any method anyway...
        return true;
    }

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

    Set<Class<?>> classes = new LinkedHashSet<>();
    // 如果是代理类,则需要返回原始类
    if (!Proxy.isProxyClass(targetClass)) {
        classes.add(ClassUtils.getUserClass(targetClass));
    }
    classes.addAll(ClassUtils.getAllInterfacesForClassAsSet(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;
}

通过上面函数大致可以理清大体脉络,首先获取对类本身进行遍历,如果不能确认是否匹配成功,那么就尝试获取类的所有接口,再连通类本身获取他们所有的方法,遍历每一个方法查看是否匹配,方法一旦匹配成功便认为这个类适用于当前增强器。匹配是通过 methodMatcher.matches() 方法实现的。methodMatcher 是通过 pc.getMethodMatcher() 获得,而 pc.getMethodMatcher() 返回的其实是 this,也就还是 pc。所以我们查看 TransactionAttributeSourcePointcutmatches() 方法

@Override
public boolean matches(Method method, Class<?> targetClass) {
   	// 判断targetClass是否是TransactionalProxy的子类或者子接口,是的话直接返回false
   	if (TransactionalProxy.class.isAssignableFrom(targetClass)) {
      	return false;
   	}
   	// 调用子类的getTransactionAttributeSource()方法
   	// 其实在构造BeanFactoryTransactionAttributeSourceAdvisor时进行了重写,返回BeanFactoryTransactionAttributeSourceAdvisor的annotationTransactionAttributeSource
   	TransactionAttributeSource tas = getTransactionAttributeSource();
   	return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}

// 模板方法,由BeanFactoryTransactionAttributeSourceAdvisor实现
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();

matches() 方法中定义了一个抽象模板函数,用于返回 TransactionAttributeSource 实例。我们能够猜到返回的就是最初我们注册的三个 beanDefinition 之一,那么究竟怎么返回的呢。其实我们在创建 BeanFactoryTransactionAttributeSourceAdvisor 中创建 TransactionAttributeSourcePointcut 实例的时候就重写了 getTransactionAttributeSource() 方法,方法内返回的就是我们注册的 AnnotationTransactionAttributeSource 实例

@Nullable
private TransactionAttributeSource transactionAttributeSource;

// 创建BeanFactoryTransactionAttributeSourceAdvisor时,默认就创建出TransactionAttributeSourcePointcut类型的pointcut
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {

   	@Override
   	@Nullable
   	protected TransactionAttributeSource getTransactionAttributeSource() {
      	return transactionAttributeSource;
   	}
};

所以 matches() 方法中返回的 tas 就是 AnnotationTransactionAttributeSource 实例。调用 getTransactionAttribute(method, targetClass) 方法来返回一个 TransactionAttribute 事务属性对象,如果返回结果不为空,那么说明这是一个匹配的增强器

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

   	// 首先查看缓存中是否有对应的处理结果
   	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);
      	// Put it in the cache.
      	if (txAttr == null) {
         	// 添加null缓存
         	this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
      	}
      	else {
         	String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
         	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;
   	}
}

getTransactionAttribute() 的函数主要目的:返回和 methodtargetClasscacheKey)对应的 TransactionAttribute 事务属性。方法中包含着缓存逻辑,spring 先尝试从缓存加载,如果不存在缓存,则通过 computeTransactionAttribute() 获取并添加到缓存。所以,重点研究 computeTransactionAttribute() 方法。当然,需要注意的是,getTransactionAttribute() 的函数最终返回 txAttrtxAttr 可能为空,空的时候表明至少该方法没有事务,说明增强器对该方法不匹配。如果类中所有的方法都不匹配,那就表明增强器不匹配该类了

提取事务注解信息

继续深入 computeTransactionAttribute() 方法。该方法中其实就是解析事务注解配置信息的过程,看来事务注解的信息对应在 spring 中的数据结构是 TransactionAttribute。解析的规则:如果方法存在事务属性,则使用方法上的属性,否则使用方法所在的类上的属性;如果方法所在类的属性上还是没有搜寻到对应的事务属性,那么再搜寻接口中的方法,再没有的话,最后尝试搜寻接口的类上面的声明

当然,在开始对方法进行事务属性搜寻之前,spring 对方法进行了判断,判断是否是 public 方法,如果不是直接返回空,也就是跳过该方法了。这也就解释我们之前介绍 spring 配置的事务如果配置到非 public 方法上就不起效果了

// 事务标签的解析提取
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
   	// Don't allow no-public methods as required.
   	if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
      	return null;
   	}
   	// method代表接口中的方法,specificMethod代表实现类中的方法
   	Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

   	// 首先查看方法是否存在事务声明
   	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;
}

computeTransactionAttribute() 函数中并没有真正的去做搜寻事务属性的逻辑,而是搭建了一个执行框架,将搜寻事务属性的任务委托给了 findTransactionAttribute() 方法去执行

// 寻找方法上是否存在事务声明
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
   	return determineTransactionAttribute(method);
}

// 寻找类或接口是否存在事务声明
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
   	return determineTransactionAttribute(clazz);
}

可以看到,无论是对方法还是类或接口,最终都交由 determineTransactionAttribute(AnnotatedElement ae) 方法去完成解析

@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement ae) {
   	for (TransactionAnnotationParser annotationParser : this.annotationParsers) {
      	TransactionAttribute attr = annotationParser.parseTransactionAnnotation(ae);
      	if (attr != null) {
         	return attr;
      	}
   	}
   	return null;
}

determineTransactionAttribute() 方法中,解析事务注解配置依靠 parse 解析类来帮助完成,这些 parse 解析类从代码上看应该是存放在 this.annotationParsers 中,而 this.annotationParsers 是当前类 AnnotationTransactionAttributeSource 中的一个 Set 集合成员

public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
      implements Serializable {

   ····

   private final boolean publicMethodsOnly;

   private final Set<TransactionAnnotationParser> annotationParsers;
   
   public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
		this.publicMethodsOnly = publicMethodsOnly;
		this.annotationParsers = new LinkedHashSet<>(2);
		this.annotationParsers.add(new SpringTransactionAnnotationParser());
		····
	}
}

可以看出在 AnnotationTransactionAttributeSource 初始化时,会给集合中添加一个解析类 SpringTransactionAnnotationParser 的实例。所以在 determineTransactionAttribute() 方法中其实委托了 SpringTransactionAnnotationParser 中的 parseTransactionAnnotation() 方法进行解析

// 解析事务注解
@Override
@Nullable
public TransactionAttribute parseTransactionAnnotation(AnnotatedElement ae) {
   	AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
         ae, Transactional.class, false, false);
   	if (attributes != null) {
      	return parseTransactionAnnotation(attributes);
   	}
   	else {
      	return null;
   	}
}

首先,先通过 AnnotatedElementUtilsfindMergedAnnotationAttributes() 方法解析 @Transactional 注解,返回 AnnotationAttributes,然后再利用 parseTransactionAnnotation() 对注解信息进行解析返回最终的事务属性实例

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

上面方法中实现了对对应类或者方法的事务注解的解析,你会在这个类中看到任何你常用或者不常用的属性提取。我们实际将事务注解信息转换成了 RuleBasedTransactionAttribute 实例进行了返回

至此,我们终于完成了事务标签的解析。我们的任务是找出某个增强器是否适合于对应的类,而是否匹配的关键则在于是否从指定的类或类中的方法中找到对应的事务属性

现在,我们是以 ProductInfoServiceImpl 为例的,已经在它的接口上找到了事务注解,那么自然就返回了不为空的 TransactionAttribute 实例,所以它是与事务增强器匹配的,也就是它会被事务功能修饰

当判断某个 bean 适用于事务增强时,也就是适用于增强器 BeanFactoryTransactionAttributeSourceAdvisor,所以说,在自定义标签解析时,注入的四个 bean 成为了整个事务功能的基础

事务增强器(重点

由于我们从容器中获取的 ProductInfoServiceImplJDK 的一个代理对象。因为是JDK动态代理,当调用目标方法时,直接执行 JdkDynamicAopProxy (实现 InvocationHandler 接口) 的 invoke() 方法

@Override
@Nullable
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 {
      	// 对 equals方法的处理
      	if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
         	return equals(args[0]);
      	}
      	// 对 hashcode方法的处理
      	else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
         	return hashCode();
      	}
      	else if (method.getDeclaringClass() == DecoratingProxy.class) {
         	return AopProxyUtils.ultimateTargetClass(this.advised);
      	}
      	// Class类的isAssignableFrom(Class cls)方法:如果调用这个方法的class或接口 与 参数cls表示的类或接口相同,
      	// 或者是参数cls表示的类或接口的父类,则返回true。例如:
      	// System.out.println(ArrayList.class.isAssignableFrom(Object.class));   --> false
      	// System.out.println(Object.class.isAssignableFrom(ArrayList.class));  --> true

      	// 如果 method所在类是Advised父类,则直接调用切点方法
      	else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
            	method.getDeclaringClass().isAssignableFrom(Advised.class)) {
         	return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
      	}

      	Object retVal;

      	// 有时候目标对象内部的自我调用将无法实施切面中的增强则需要通过此属性暴露代理至ThreadLocal中
      	if (this.advised.exposeProxy) {
         	// 将代理类对象proxy保存到ThreadLocal中,同时获取之前存储的oldProxy
         	oldProxy = AopContext.setCurrentProxy(proxy);
         	setProxyContext = true;
      	}

      	// 获取目标对象及类型
      	target = targetSource.getTarget();
      	Class<?> targetClass = (target != null ? target.getClass() : null);

      	// 获取当前方法的拦截器链(之前我们找的增强器统一封装成了拦截器链)
      	List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

      	if (chain.isEmpty()) {
         	// 如果没有发现任何拦截器那么直接调用切点方法
         	Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         	retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
      	}
      	else {
         	// 将拦截器封装在ReflectiveMethodInvocation,以便于使用下面的 proceed进行链接调用拦截器
         	invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
         	// 执行拦截器链中每个拦截器的 invoke 方法
         	retVal = invocation.proceed();
      	}

      	// 返回结果
      	Class<?> returnType = method.getReturnType();
      	if (retVal != null && retVal == target &&
            	returnType != Object.class && returnType.isInstance(proxy) &&
            !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
         	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()) {
         	targetSource.releaseTarget(target);
      	}
      	if (setProxyContext) {
         	AopContext.setCurrentProxy(oldProxy);
      	}
   	}
}

getInterceptorsAndDynamicInterceptionAdvice() 方法获得的拦截器调用链 chain 内容其实只有 TransactionInterceptor 一个,TransactionInterceptor 实现了 MethodInterceptor 接口。最终会调用每个 MethodInterceptorinvoke 方法

随后进行拦截器的逐一调用,调用的其实是:执行拦截器中的 invoke() 方法

@Override
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {

	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

targetClass 就是 ProductInfoServiceImpl 的全限定类名

invokeWithinTransaction() 方法,是 spring 事务管理的核心方法
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
      final InvocationCallback invocation) throws Throwable {

   	// 1. 获取对应配置的事务属性,事务属性保存在 AnnotationTransactionAttributeSource中
   	TransactionAttributeSource tas = getTransactionAttributeSource();
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
   	// 2. 获取 beanFactory 中的 transactionManager
   	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
   	// 构造方法唯一标识(类.方法,如xxx.xxx.service.ActorServiceImpl.save)
   	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

   	// 3. 对不同的事务处理方式使用不同的逻辑,包括声明式和编程式
   	// 声明式事务处理
   	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {

      	// 4. 创建TransactionInfo,在目标方法执行前获取事务并收集事务信息
      	TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
      	Object retVal = null;
      	try {
         	// 5. 执行被增强方法
         	retVal = invocation.proceedWithInvocation();
      	}
      	catch (Throwable ex) {
         	// 6. 异常回滚
         	completeTransactionAfterThrowing(txInfo, ex);
         	throw ex;
      	}
      	finally {
         	// 7. 清除信息
         	cleanupTransactionInfo(txInfo);
      	}
      	// 8. 提交事务
      	commitTransactionAfterReturning(txInfo);
      	return retVal;
   	}
   	// 编程式事务处理
   	else {
      	final ThrowableHolder throwableHolder = new ThrowableHolder();
      	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)) {
                  if (ex instanceof RuntimeException) {
                     throw (RuntimeException) ex;
                  }
                  else {
                     throw new ThrowableHolderException(ex);
                  }
               }
               	else {
                  	throwableHolder.throwable = ex;
                  	return null;
               	}
            }
            	finally {
               		cleanupTransactionInfo(txInfo);
            	}
         	});

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

该方法就是我们需要着重研究的对象,我们尝试整理下事务处理的脉络,在 spring 中支持两种事务处理的方式,分别是声明式事务处理与编程式事务处理,两者相对于开发人员来讲差别很大,考虑到对事务的应用比声明式的事务处理使用起来方便,也相对流行些,我们就分析声明式事务

声明式事务处理主要有以下步骤
  1. 获取事务的属性。对于事务处理来说,最基础或者说最首要的工作便是获取事务属性了,这是支撑整个事务功能的基石,在前面我们已经分析了事务属性提取,保存在了 AnnotationTransactionAttributeSource
  2. 加载配置文件中配置的 TransactionManager
  3. 不同的事务处理方式使用不同的逻辑。主要是声明式事务和编程式事务之分
  4. 创建 TransactionInfo,在目标方法执行前获取事务并收集事务信息
  5. 执行目标(被代理类的)方法。注意该方法的调用时机
  6. 一旦出现异常,尝试异常处理。并不是所有异常,spring 都会将其回滚,默认只对 RuntimeExceptionError 两种情况会进行回滚处理
  7. 提交事务前将事务信息清除
  8. 提交事务

对于 8 步以上详情:Spring源码—事务

执行目标方法

这一部分在 AOP 中已经分析过,主要是进行事务拦截器调用完就执行目标本身方法

回滚处理

一旦出现 Throwable 就会被引导至 completeTransactionAfterThrowing() 方法处理

try {
    // 5. 执行被增强方法
	retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
    // 6. 异常回滚
    completeTransactionAfterThrowing(txInfo, ex);
    throw ex;
}

处理异常不代表所有的 Throwable 都会被回滚处理,比如我们最常用的 Exception 默认是不会被处理的。默认情况下,即使出现异常,数据也会被正常提交,而是否回滚,关键就是在 txInfo.transactionAttribute.rollbackOn(ex) 这个函数

// spring对于异常的处理
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
   // 当抛出异常时首先判断当前是否存在事务,这是基础依据
	if (txInfo != null && txInfo.getTransactionStatus() != null) {
      	if (logger.isTraceEnabled()) {
         	logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() +
               "] after exception: " + ex);
      	}
      	// 这里判断是否回滚默认的依据是抛出的异常是否是RuntimeException或者是Error的类型
      	if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
         	try {
            	// 根据TransactionStatus信息进行回滚处理
            	txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
         	}
         	catch (TransactionSystemException ex2) {
            	logger.error("Application exception overridden by rollback exception", ex);
            	ex2.initApplicationException(ex);
            	throw ex2;
         	}
         	catch (RuntimeException | Error ex2) {
            	logger.error("Application exception overridden by rollback exception", ex);
           		throw ex2;
         	}
      	}
      	else {
         	// 如果不满足回滚条件即使抛出异常也同样会提交
         	try {
            	txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
         	}
        	 catch (TransactionSystemException ex2) {
            	logger.error("Application exception overridden by commit exception", ex);
            	ex2.initApplicationException(ex);
            	throw ex2;
         	}
         	catch (RuntimeException | Error ex2) {
            	logger.error("Application exception overridden by commit exception", ex);
            	throw ex2;
         	}
      	}
   	}
}

spring 的事务回滚条件

  • 如果事务注解中配置有 rollbackForrollbackForClassName,则进行遍历,如果符合规则,则返回 true,即事务需要回滚
  • 如果事务注解中没有配置回滚规则,默认情况下 spring 只对 RuntimeExceptionError 两种情况会进行回滚处理
spring 之事务步骤小结
  1. spring 容器初始化启动时,会去解析所有的配置文件,将配置文件中的 bean 定义封装成 BeanDefinition,加载到 BeanFactory
  2. 在事务 annotation-driven 标签的的解析过程中,会向 IOC 容器中注册四个 bean分别为:InfrastructureAdvisorAutoProxyCreator,TransactionAttributeSource,TransactionInterceptor,TransactionAttributeSourceAdvisor
  3. 同时,在 spring 容器初始化启动时,会完成向 IOC 容器中注册 bean 的工作。在注册的过程中,会去判断这些 bean 需不需要被代理(获取 bean 的事务或非事务增强器,有则需要代理,反之,不需要代理
  4. 如果不需要,则直接返回原始单例 bean,此时单例 bean 已完成向 IOC 容器的注册工作
  5. 如果需要,再确定代理方式是使用 JDK 代理,还是使用 Cglib,去创建代理对象Spring Aop代理对象的产生(二)
  6. 当使用被代理对象调用被代理类的方法时,实际上是使用代理对象调用 invoke() 方法,也就是调用到了声明式的事务相关的处理(invokeWithinTransaction()方法是 spring 事务管理的核心)
spring 之事务理论小结

在应用系统调用声明 @Transactional 的目标方法或类时,spring 默认使用 AOP 代理,在代码运行时生成一个代理对象,根据 @Transactional 的属性配置信息,由这个代理对象决定该声明 @Transactional 的目标方法是否由拦截器 TransactionInterceptor 来使用拦截,在 TransactionInterceptor 拦截时,会在目标方法开始执行之前创建并加入事务,并执行目标方法的逻辑,,最后根据执行情况是否出现异常,利用事务管理器PlatformTransactionManager 操作数据源 DataSource 提交或回滚事务

参考:Spring源码—事务

收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据