spring事务分析

本文深入探讨了Spring事务的源码分析,包括@EnableTransactionManagement的作用、TransactionInterceptor如何处理事务,以及如何判断事务是否应该回滚。在源码解析中,详细介绍了bean的增强过程、事务开启和提交,特别指出事务回滚判断不仅考虑异常类型,还涉及异常的递归检查。
spring事务源码分析

说到事务就离不开两个注解EnableTransactionManagement和 @Transactional注解。注意:如果光加@Transactional而没有EnableTransactionManagement事务是不生效的

@EnableTransactionManagement其中采用了import机制,引入了TransactionManagementConfigurationSelector类。这个import机制常常用来引入第三方的插件

protected String[] selectImports(AdviceMode adviceMode) {
		switch (adviceMode) {
			case PROXY:
				return new String[] {AutoProxyRegistrar.class.getName(),
						ProxyTransactionManagementConfiguration.class.getName()};
			case ASPECTJ:
				return new String[] {determineTransactionAspectClass()};
			default:
				return null;
		}
	}

@EnableTransactionManagement默认的adviceMode为PROXY,
这个import引入了两个类到spring容器中AutoProxyRegistrar和ProxyTransactionManagementConfiguration

  1. 先看AutoProxyRegistrar这个类的作用
    这个类是ImportBeanDefinitionRegistrar的子类,用于向容器中自定义添加beanDefinition。
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		boolean candidateFound = false;
		Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
		for (String annType : annTypes) {
			AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
			if (candidate == null) {
				continue;
			}
			Object mode = candidate.get("mode");
			Object proxyTargetClass = candidate.get("proxyTargetClass");
			if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
					Boolean.class == proxyTargetClass.getClass()) {
				candidateFound = true;
				if (mode == AdviceMode.PROXY) {
					AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
					if ((Boolean) proxyTargetClass) {
						AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
						return;
					}
				}
			}
		}
	}

主要是注册了一个BeanDefinition 类型为InfrastructureAdvisorAutoProxyCreator,其实SmartInstantiationAwareBeanPostProcessor的子类,基于spring的beanPostprocessor机制,是用于在bean创建的过程中对bean做增强用的。在我们具体的bean创建期间再说。类似于aop

  1. ProxyTransactionManagementConfiguration
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
}

这个类就是一个简单的配置类,我们先看其父类AbstractTransactionManagementConfiguration

@Configuration
public abstract class AbstractTransactionManagementConfiguration implements ImportAware {

	@Nullable
	protected AnnotationAttributes enableTx;

	/**
	 * Default transaction manager, as configured through a {@link TransactionManagementConfigurer}.
	 */
	@Nullable
	protected PlatformTransactionManager txManager;


	@Override
	public void setImportMetadata(AnnotationMetadata importMetadata) {
		this.enableTx = AnnotationAttributes.fromMap(
				importMetadata.getAnnotationAttributes(EnableTransactionManagement.class.getName(), false));
		if (this.enableTx == null) {
			throw new IllegalArgumentException(
					"@EnableTransactionManagement is not present on importing class " + importMetadata.getClassName());
		}
	}

	@Autowired(required = false)
	void setConfigurers(Collection<TransactionManagementConfigurer> configurers) {
		if (CollectionUtils.isEmpty(configurers)) {
			return;
		}
		if (configurers.size() > 1) {
			throw new IllegalStateException("Only one TransactionManagementConfigurer may exist");
		}
		TransactionManagementConfigurer configurer = configurers.iterator().next();
		this.txManager = configurer.annotationDrivenTransactionManager();
	}


	@Bean(name = TransactionManagementConfigUtils.TRANSACTIONAL_EVENT_LISTENER_FACTORY_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public static TransactionalEventListenerFactory transactionalEventListenerFactory() {
		return new TransactionalEventListenerFactory();
	}

创建了TransactionalEventListenerFactory的工厂,以及解析注解拿到实物管理器txManger和@EnableTransactionManagement事务注解的属性.
继续看子类

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {

	@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
		BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
		advisor.setTransactionAttributeSource(transactionAttributeSource());
		advisor.setAdvice(transactionInterceptor());
		if (this.enableTx != null) {
			advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
		}
		return advisor;
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionAttributeSource transactionAttributeSource() {
		return new AnnotationTransactionAttributeSource();
	}

	@Bean
	@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
	public TransactionInterceptor transactionInterceptor() {
		TransactionInterceptor interceptor = new TransactionInterceptor();
		interceptor.setTransactionAttributeSource(transactionAttributeSource());
		if (this.txManager != null) {
			interceptor.setTransactionManager(this.txManager);
		}
		return interceptor;
	}

}

创建了事务的advisor,advisor封装了增强和pointcut相关信息
创建了TransactionAttributeSource的bean
创建了advise TransactionInterceptor是methodInterceptor的子类。在执行具体方法的时候做增强;

在回到最开始InfrastructureAdvisorAutoProxyCreator我们看具体在哪里生效。其实这部分和aop是一致的,就是在bean初始化完成之后对bean是否需要进行代理来做判断。如何判断是否当前bean是否支持的advisor

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) {
			// 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;
	}

中间调用过多我们直接看最终调用匹配的方法

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
		// 如果只允许public方法但是当前修饰符不是public的话返回null
		if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
			return null;
		}
        //找到真实的方法
		// The method may be on an interface, but we need attributes from the target class.
		// If the target class is null, the method will be unchanged.
		Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);

		// First try is the method in the target class.
        //看下当前方法是否贴有@Transactional注解,解析并返回
		TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
		if (txAttr != null) {
			return txAttr;
		}
        //看当前方法对应的类是否贴有@Transactional注解,解析并返回
		// Second try is the transaction attribute on the target class.
		txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
		if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
			return txAttr;
		}

		if (specificMethod != method) {
			// Fallback is to look at the original method.
			txAttr = findTransactionAttribute(method);
			if (txAttr != null) {
				return txAttr;
			}
			// Last fallback is the class of the original method.
			txAttr = findTransactionAttribute(method.getDeclaringClass());
			if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
				return txAttr;
			}
		}

		return null;
	}

如果符合的话最终会canApply最终会返回true,然后进入动态代理阶段。动态代理其实都差不多。这里就不过多讲了

进入调用阶段
调用阶段因为动态代理会进入方法拦截,以CGLIB为例,第一个进入DynamicAdvisedInterceptor方法.拦截之后会进入熟悉的aop的advise链式调用,责任链模式。先忽略,直接接入我们transactional的advise TransactionInterceptor

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);

			Object retVal;
			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);
			

invocation.proceedWithInvocation();为我们真实要调用的方法
createTransactionIfNecessary 事务开启设置手动提交
completeTransactionAfterThrowing 事务异常判断异常类型是否需要进行回滚
commitTransactionAfterReturning 进行事务提交

createTransactionIfNecessary会调用DataSourceTransactionManager的doBegin方法开启一个事务
其中会调用我们经典的connection.setAutoCommit(false);

事务的回滚下面?这个章节有介绍.

事务的最终提交也不用将了。。。。忽略。

spring如何判断当前事务是否应该回滚

在没有看到源码的我理所应当的认为是判断异常类型是否相同这么简单。但是当我做了下面一个测试的时候发现和我想的完全不一样。

    @Transactional(rollbackFor = BizException.class)
    public void saveUser(User user){

        this.userService.SaveUser(user);
        int i = 1/0;
    }

前面的代码1/0会抛出一个ArithmeticException是RuntimeException的子类,BizException是我们自定义的异常也是runtimeException的子类。结果我发现竟然被回滚了。。。

所以再来看下源码。
@Transactonal对应的advice是TransactionInterceptor,当我们调用方法的时候执行的是invokeWithinTransaction方法

try {
                result = invocation.proceedWithInvocation();
            } catch (Throwable var17) {
                this.completeTransactionAfterThrowing(txInfo, var17);
                throw var17;
            } finally {
                this.cleanupTransactionInfo(txInfo);
            }

当发生异常的时候会调用completeTransactionAfterThrowing方法进行事务回滚的异常判断。

      protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
        if (txInfo != null && txInfo.getTransactionStatus() != null) {
            if (this.logger.isTraceEnabled()) {
                this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
            }

            if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
                try {
                    txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var6) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    var6.initApplicationException(ex);
                    throw var6;
                } catch (Error | RuntimeException var7) {
                    this.logger.error("Application exception overridden by rollback exception", ex);
                    throw var7;
                }
            } else {
                try {
                    txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
                } catch (TransactionSystemException var4) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    var4.initApplicationException(ex);
                    throw var4;
                } catch (Error | RuntimeException var5) {
                    this.logger.error("Application exception overridden by commit exception", ex);
                    throw var5;
                }
            }
        }

    }

上面的逻辑代码是比较清晰的,判断当前异常类型我们回滚限定的类型,逻辑在txInfo.transactionAttribute.rollbackOn(ex))方法

	public boolean rollbackOn(Throwable ex) {
		RollbackRuleAttribute winner = null;
		int deepest = Integer.MAX_VALUE;
    
		if (this.rollbackRules != null) {
        //循环取出rule 就是我们的rollbackFor的Class<? extends Throwable>[]
			for (RollbackRuleAttribute rule : this.rollbackRules) {
            //这里为了取出层级,什么意思呢?如果当前抛出的异常是rollbackFor中的多个异常类的子类,
            //取出当前最近的那个进行rollback,如果没有匹配的上的那么就是-1 
				int depth = rule.getDepth(ex);
				if (depth >= 0 && depth < deepest) {
					deepest = depth;
					winner = rule;
				}
			}
		}

		if (logger.isTraceEnabled()) {
			logger.trace("Winning rollback rule is: " + winner);
		}

		//如果没有异常匹配的上的话就会调用父类的默认的rollbackon规则。
        //父类的规则判断是继承与runtimeException或者是继承与Error。。。
		if (winner == null) {
			logger.trace("No relevant rollback rule found: applying default rules");
			return super.rollbackOn(ex);
		}
        //如果最终拿到的是不需要回滚的rule的话也是不回滚的
		return !(winner instanceof NoRollbackRuleAttribute);
	}
	父类的判断是否回滚的判断

public boolean rollbackOn(Throwable ex) {
return (ex instanceof RuntimeException || ex instanceof Error);
}

getDepth的代码如下:很简单的一个递归,不做过多的解释了。

public int getDepth(Throwable ex) {
		return getDepth(ex.getClass(), 0);
	}


	private int getDepth(Class<?> exceptionClass, int depth) {
		if (exceptionClass.getName().contains(this.exceptionName)) {
			// Found it!
			return depth;
		}
		// If we've gone as far as we can go and haven't found it...
		if (exceptionClass == Throwable.class) {
			return -1;
		}
		return getDepth(exceptionClass.getSuperclass(), depth + 1);
	}

上面的代码说实话对我来说有点颠覆。
1.首先异常的判断是会递归判断父级的。这个以前没有仔细研究过
2.然后如果最终没有匹配的上exception的话会最终判断当前抛出的异常是否是runtimeException的子类或者是Error的子类,然后最终判断是否回滚。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值