Spring事务源码解析(声明式事务)

切入点:

spring自定义标签的解析

上面的resolve方法点进去,执行TxNamespaceHandler.init()方法

以上两个parser分别用来解析tx:advice和tx:annotation-driven标签。

进行标签解析:

调用parser.parse()方法进行解析:

最外围的if判断限制了<tx:annotation-driven/>标签只能被解析一次,所以只有第一次被解析的标签会生效。蓝色框的部分分别注册了三个BeanDefinition,分别为AnnotationTransactionAttributeSource、TransactionInterceptor和BeanFactoryTransactionAttributeSourceAdvisor,并将前两个BeanDefinition添加到第三个BeanDefinition的属性当中,这三个bean支撑了整个事务功能。

我们先来看红色框的第一个方法:

还记得当<tx:annotation-driven/>标签在不指定transaction-manager属性的时候,会默认寻找id固定名为transactionManager的bean作为事务管理器这个注意事项么,就是在这里实现的。

下面我们来看红色框的第二个方法:

这里可以看到,注册了一个InfrastructureAdvisorAutoProxyCreator类型的Bean。

其实InfrastructureAdvisorAutoProxyCreator是一个BeanPostProcessor

其父类AbstractAutoProxyCreator重写了postProcessAfterInitialization,如下:

先来看方法1:

先找出所有对应Advisor的类的beanName,再通过beanFactory.getBean方法获取这些bean并返回。

还记得前面提到的三个类,其中BeanFactoryTransactionAttributeSourceAdvisor实现了Advisor接口,所以这个bean就会在此被提取出来,而另外两个bean被织入了BeanFactoryTransactionAttributeSourceAdvisor当中,所以也会一起被提取出来,下图为BeanFactoryTransactionAttributeSourceAdvisor类的层次:

下面让我们来看Spring如何在所有候选的增强器中获取匹配的增强器:

上面的方法中提到引介增强的概念,在此做简要说明,引介增强是一种比较特殊的增强类型,它不是在目标方法周围织入增强,而是为目标类创建新的方法和属性,所以引介增强的连接点是类级别的,而非方法级别的。通过引介增强,我们可以为目标类添加一个接口的实现,即原来目标类未实现某个接口,通过引介增强可以为目标类创建实现该接口的代理。另外这个方法用两个重载的canApply方法为目标类寻找匹配的增强器,其中第一个canApply方法会调用第二个canApply方法并将第三个参数传为false:

在上面BeanFactoryTransactionAttributeSourceAdvisor类的层次中我们看到它实现了PointcutAdvisor接口,所以会调用红框中的canApply方法进行判断,第一个参数pca.getPointcut()也就是调用BeanFactoryTransactionAttributeSourceAdvisor的getPointcut方法:

这里的transactionAttributeSource也就是我们在文章开始看到的为BeanFactoryTransactionAttributeSourceAdvisor织入的两个bean中的AnnotationTransactionAttributeSource,我们以TransactionAttributeSourcePointcut作为第一个参数继续跟踪canApply方法:

我们跟踪pc.getMethodMatcher()方法也就是TransactionAttributeSourcePointcut的getMethodMatcher方法是在它的父类中实现:

发现方法直接返回this,也就是下面methodMatcher.matches方法就是调用TransactionAttributeSourcePointcut的matches方法:

在上面我们看到其实这个tas就是AnnotationTransactionAttributeSource,这里的目的其实也就是判断我们的业务方法或者类上是否有@Transactional注解,跟踪AnnotationTransactionAttributeSource的getTransactionAttribute方法(在其父类AbstractFallbackTransactionAttributeSource中):

我们来看看上图中的第一个方法 computeTransactionAttribute:

方法中的事务声明优先级最高,如果方法上没有声明则在类上寻找:

this.annotationParsers是在AnnotationTransactionAttributeSource类初始化的时候初始化的:

所以annotationParser.parseTransactionAnnotation就是调用SpringTransactionAnnotationParser的parseTransactionAnnotation方法:

至此,我们终于看到的Transactional注解,下面无疑就是解析注解当中声明的属性了:

在这个方法中我们看到了在Transactional注解中声明的各种常用或者不常用的属性的解析,

至此,事务的初始化工作算是完成了,下面开始真正的进入执行阶段。

以JDK动态代理为例,调用的是JdkDynamicAopProxy的invoke()方法。

第一步:

获取方法的拦截器链(所有要执行的 advice)

注:这里的advisors是在后置处理的时候放进去的:

MethodInterceptor[] interceptors = registry.getInterceptors(advisor);

这一步的作用是,获取当前advisor的advice,即拦截器,这里指的就是

BeanFactoryTransactionAttributeSourceAdvisor的advice->TransactionInterceptor

1.如果advice是MethodInterceptor类型,则直接添加;

2.如果advice不是MethodInterceptor类型,但是是通知适配器支持的类型,比如:

@Before  @AfterReturning  @AfterThrowing等类型的通知,则转成MethodInterceptor类型。

第二步:

创建方法调用器,调用proceed()方法执行拦截器链

然后调用TransactionInterceptor.invoke()方法

protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
			final InvocationCallback invocation) throws Throwable {

		if (this.reactiveAdapterRegistry != null) {
			ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
			if (adapter != null) {
				return new ReactiveTransactionSupport(adapter).invokeWithinTransaction(method, targetClass, invocation);
			}
		}

		// If the transaction attribute is null, the method is non-transactional.
		// 获取事务属性信息
		TransactionAttributeSource tas = getTransactionAttributeSource();
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		// 确定transactionManager
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		// 获取方法的全限定名
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		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
				// catch到异常,则完成事务(提交或回滚事务)
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
				cleanupTransactionInfo(txInfo);
			}

			if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
				// Set rollback-only in case of Vavr failure matching our rollback rules...
				TransactionStatus status = txInfo.getTransactionStatus();
				if (status != null && txAttr != null) {
					retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
				}
			}

			// 执行成功,则完成事务(提交事务)
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}

		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 {
						Object retVal = invocation.proceedWithInvocation();
						if (vavrPresent && VavrDelegate.isVavrTry(retVal)) {
							// Set rollback-only in case of Vavr failure matching our rollback rules...
							retVal = VavrDelegate.evaluateTryFailure(retVal, txAttr, status);
						}
						return retVal;
					}
					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;
			}
		}
	}

 这个方法很长,但是整体逻辑还是非常清晰的,首选获取事务属性,这里的getTransactionAttrubuteSource()方法的返回值同样是在开始我们看到的被织入到TransactionInterceptor中的AnnotationTransactionAttributeSource,在事务准备阶段已经解析过事务属性并保存到缓存中,所以这里会直接从缓存中获取,接下来获取配置的TransactionManager,也就是determineTransactionManager方法,这里如果配置没有指定transaction-manager并且也没有默认id名为transactionManager的bean,就会报错,然后是针对声明式事务和编程式事务的不同处理,创建事务信息,执行目标方法,最后根据执行结果进行回滚或提交操作。

我们先分析创建事务的过程。在分析之前希望大家能先去了解一下Spring的事务传播行为,有助于理解下面的源码,

这里做一个简要的介绍,更详细的信息请大家自行查阅Spring官方文档,里面有更新详细的介绍。

Spring的事务传播行为定义在Propagation这个枚举类中,一共有七种,分别为:

REQUIRED:支持使用当前事务,如果当前事务不存在,则自己新建一个新的事务,是默认的事务传播行为

NOT_SUPPORTED:不使用事务,如果当前存在事务,则将当前事务挂起。

REQUIRES_NEW:创建一个新的事务,如果当前事务已存在,则将当前事务挂起。

MANDATORY:有强制的意思,支持使用当前事务,如果事务不存在,则直接抛出Exception。

SUPPORTS:支持使用当前事务,如果当前事务不存在,则不使用事务。

NEVER:无事务,如果存在事务,则直接抛出Exception。

NESTED:如果当前存在事务,则在嵌套的事务中运行。如果当前没有事务,则等同于REQUIRED。内部事务的回滚不会对外部事务造成影响,

它只对DataSourceTransactionManager事务管理器起效。

下面我们来分析事务创建的过程:

先来看第一个方法:

第一个方法doGetTransaction:

org.springframework.jdbc.datasource.DataSourceTransactionManager#doGetTransaction

第二个方法isExistingTransaction:

org.springframework.jdbc.datasource.DataSourceTransactionManager#isExistingTransaction

判断当前线程是否存在事务就是判断记录的数据库连接是否为空并且transactionActive状态为true。

第三个方法handleExistingTransaction:

private TransactionStatus handleExistingTransaction(
			TransactionDefinition definition, Object transaction, boolean debugEnabled)
			throws TransactionException {

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NEVER) {
			throw new IllegalTransactionStateException(
					"Existing transaction found for transaction marked with propagation 'never'");
		}

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction");
			}
			Object suspendedResources = suspend(transaction);
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(
					definition, null, false, newSynchronization, debugEnabled, suspendedResources);
		}

		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {
			if (debugEnabled) {
				logger.debug("Suspending current transaction, creating new transaction with name [" +
						definition.getName() + "]");
			}
			// 新事务的建立,挂起旧事务
			SuspendedResourcesHolder suspendedResources = suspend(transaction);
			try {
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
				// 开启事务
				doBegin(transaction, definition);
				// 同步事务状态
				prepareSynchronization(status, definition);
				return status;
			}
			catch (RuntimeException | Error beginEx) {
				resumeAfterBeginException(transaction, suspendedResources, beginEx);
				throw beginEx;
			}
		}

		// 嵌套事务处理
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			if (!isNestedTransactionAllowed()) {
				throw new NestedTransactionNotSupportedException(
						"Transaction manager does not allow nested transactions by default - " +
						"specify 'nestedTransactionAllowed' property with value 'true'");
			}
			if (debugEnabled) {
				logger.debug("Creating nested transaction with name [" + definition.getName() + "]");
			}
			if (useSavepointForNestedTransaction()) {
				// Create savepoint within existing Spring-managed transaction,
				// through the SavepointManager API implemented by TransactionStatus.
				// Usually uses JDBC 3.0 savepoints. Never activates Spring synchronization.
				DefaultTransactionStatus status =
						prepareTransactionStatus(definition, transaction, false, false, debugEnabled, null);
				status.createAndHoldSavepoint();
				return status;
			}
			else {
				// Nested transaction through nested begin and commit/rollback calls.
				// Usually only for JTA: Spring synchronization might get activated here
				// in case of a pre-existing JTA transaction.
				boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
				DefaultTransactionStatus status = newTransactionStatus(
						definition, transaction, true, newSynchronization, debugEnabled, null);
				doBegin(transaction, definition);
				prepareSynchronization(status, definition);
				return status;
			}
		}

		// Assumably PROPAGATION_SUPPORTS or PROPAGATION_REQUIRED.
		if (debugEnabled) {
			logger.debug("Participating in existing transaction");
		}
		if (isValidateExistingTransaction()) {
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
				Integer currentIsolationLevel = TransactionSynchronizationManager.getCurrentTransactionIsolationLevel();
				if (currentIsolationLevel == null || currentIsolationLevel != definition.getIsolationLevel()) {
					Constants isoConstants = DefaultTransactionDefinition.constants;
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] specifies isolation level which is incompatible with existing transaction: " +
							(currentIsolationLevel != null ?
									isoConstants.toCode(currentIsolationLevel, DefaultTransactionDefinition.PREFIX_ISOLATION) :
									"(unknown)"));
				}
			}
			if (!definition.isReadOnly()) {
				if (TransactionSynchronizationManager.isCurrentTransactionReadOnly()) {
					throw new IllegalTransactionStateException("Participating transaction with definition [" +
							definition + "] is not marked as read-only but existing transaction is");
				}
			}
		}
		boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
		return prepareTransactionStatus(definition, transaction, false, newSynchronization, debugEnabled, null);
	}

REQUIRESNEW会开启一个新事务并挂起原事务,当然开启一个新事务就需要一个新的数据库连接:

suspend挂起操作主要目的是将当前connectionHolder置为null,保存原有事务信息,以便于后续恢复原有事务,

并将当前正在进行的事务信息进行重置。下面我们看Spring如何开启一个新事务:

这里我们看到了数据库连接的获取,如果是新事务需要获取新一个新的数据库连接,并为其设置了隔离级别、是否只读等属性,

下面就是将事务信息记录到当前线程中:

接下来就是记录事务状态并返回事务信息:

然后就是我们目标业务方法的执行了,根据执行结果的不同做提交或回滚操作,我们先看一下回滚操作:

红框里的方法,实际调用的是RuleBasedTransactionAttribute.rollbackOn()方法:

其中,rollbackRules就是我们@Transactional注解里的rollbackFor属性所配置的,

它是在tx自定义标签解析的时候放进去的:

rule.getDepth(ex)方法逻辑如下:

super.rollbackOn(ex)即DefaultTransactionAttribute的rollbackOn方法:

接下来执行真正的回滚操作:

以上方法1,有保存点;

方法2:,是新事务;

方法3,加入到已有的事物

最后,清除事务信息:

保存点一般用于嵌入式事务,内嵌事务的回滚不会引起外部事务的回滚。下面我们来看新事务的回滚:

很简单,就是获取当前线程的数据库连接并调用其rollback方法进行回滚,使用的是底层数据库连接提供的API。

最后还有一个清理和恢复挂起事务的操作:

事务挂起操作:

如果事务执行前有事务挂起,那么当前事务执行结束后需要将挂起的事务恢复,挂起事务时保存了原事务信息,

重置了当前事务信息,所以恢复操作就是将当前的事务信息设置为之前保存的原事务信息。

到这里事务的回滚操作就结束了,下面让我们来看事务的提交操作:

在上文分析回滚流程中我们提到了如果当前事务不是独立的事务,也没有保存点,在回滚的时候只是设置一个回滚标记,

由外部事务提交时统一进行整体事务的回滚。如下:

最后执行processCommit方法:

提交操作也是很简单的调用数据库连接底层API的commit方法:

至此,Spring事务的源码分析结束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章