spring aop(三):spring声明式事务源码详解

1. 前言

在介绍spring的事务之前,我们通过一篇博客学习下spring事务的相关概念。以便我们后面的讲解。
《spring事务详解》
spring的事务,可以分为声明式事务和编程式事务两种。本章介绍的是声明式事务。

2. xml配置文件

对于spring的声明式事务,我们可以通过xml配置文件进行配置,也可以使用注解进行配置。以下为配置文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--外部配置文件,指定数据库的配置-->
    <context:property-placeholder location="classpath:db.properties" />
    <!--业务bean-->
    <bean id="userService" class="com.lihui.study.spring.service.impl.UserServiceImpl">
        <property name="name" value="张学友"/>
    </bean>
    <!--配置数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driverClassName}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <property name="initialSize" value="${initialSize}"/>
        <property name="validationQuery" value="${validationQuery}"/>
    </bean>
    <!--配置事务管理器-->
    <bean id="transactionManager1"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置事务的传播特性等参数-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager1">
        <tx:attributes>
            <tx:method name="add*" isolation="READ_COMMITTED" propagation="REQUIRED" rollback-for="Exception"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!--配置事务需要管理的类-->
    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com.lihui.study.spring.service..*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
    </aop:config>
</beans>

3<tx:advice>标签解析流程

3.1 tx命名空间对应的处理类 :TxNamespaceHandler

与上一篇<aop:config>标签的解析相同,<tx:advice>标签也会通过相同的策略找到相应的标签处理类TxNamespaceHandler。同样,是实例化TxNamespaceHandler之后,调用init()方法进行初始化,然后再进行相应的解析逻辑。

public void init() {
		registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());
		registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
		registerBeanDefinitionParser("jta-transaction-manager", new JtaTransactionManagerBeanDefinitionParser());
	}

3.2 <tx:advice>标签解析类:TxAdviceBeanDefinitionParser

在上一节已经注册了advice的解析器,所以<tx:advice>标签最终会被TxAdviceBeanDefinitionParser进行解析,最后会调用TxAdviceBeanDefinitionParser.doParse()方法解析这个标签。最终会注册一个TransactionInterceptor.class的bean定义,id为txAdvice。

//解析最终生产的bean定义的bean类型
protected Class<?> getBeanClass(Element element) {
		return TransactionInterceptor.class;
	}
	
	//设置TransactionInterceptor的transactionAttributeSource属性
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
		builder.addPropertyReference("transactionManager", TxNamespaceHandler.getTransactionManagerName(element));

		List<Element> txAttributes = DomUtils.getChildElementsByTagName(element, ATTRIBUTES_ELEMENT);
		if (txAttributes.size() > 1) {
			parserContext.getReaderContext().error(
					"Element <attributes> is allowed at most once inside element <advice>", element);
		}
		else if (txAttributes.size() == 1) {
			// Using attributes source.
			// 如果是一个<tx:attributes>子标签,那么会生成一个NameMatchTransactionAttributeSource类的bean定义,里面封装了<tx:attributes>标签下的方法名匹配、隔离级别、传播行为、异常回滚、是否只读等信息。
			Element attributeSourceElement = txAttributes.get(0);
			RootBeanDefinition attributeSourceDefinition = parseAttributeSource(attributeSourceElement, parserContext);
			builder.addPropertyValue("transactionAttributeSource", attributeSourceDefinition);
		}
		else {
			// Assume annotations source.
			//没有<tx:attributes>子标签,也就是没有配置事务的相关配置。那么返回一个给予注解的事务属性源AnnotationTransactionAttributeSource的定义。
			builder.addPropertyValue("transactionAttributeSource",
					new RootBeanDefinition("org.springframework.transaction.annotation.AnnotationTransactionAttributeSource"));
		}
	}

3.3 事务切面TransactionInterceptor与代理构建器的关联

在aop:config标签的解析,生成、注册AspectJAwareAdvisorAutoProxyCreator 自动代理构建器时,txAdvice(TransactionInterceptor.class)会被注入到advisedBeans属性中。也就是在这里实现了事务切面txAdvice和自动代理构建器的关联。最后通过自动代理构建器创建代理对象时,会把事务的切面织入进去。

4. 事务的执行流程

在上文中,我们知道事务切面 ixAdvice(TransactionInterceptor类)已经织入到了拦截器链中。最终,是通过调用TransactionInterceptor.invoke()方法来实现的,以下为相应执行流程的源码解析。

4.1 TransactionInterceptor.invoke()

public Object invoke(MethodInvocation invocation) throws Throwable {
		// Work out the target class: may be {@code null}.
		// The TransactionAttributeSource should be passed the target class
		// as well as the method, which may be from an interface.
		//获取代理的目标对象。可能为null
		Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

		// Adapt to TransactionAspectSupport's invokeWithinTransaction...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
	}

4.2 TransactionAspectSupport.invokeWithinTransaction()

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

		// If the transaction attribute is null, the method is non-transactional.
		/**
		* 获取事务属性源,在前文中接受过,在xml解析时,已经将<tx:advice>标签下的<tx:attributes>元素封
		* 装成表示事务相关配置的NameMatchTransactionAttributeSource或者AnnotationTransactionAttributeSource,
		* 注入在txAdvice bean中,所以这里可以获取到。
		**/
		TransactionAttributeSource tas = getTransactionAttributeSource();
		//根据方法名和目标对象找到相应的那一组事务属性配置(包括隔离级别、传播行为、回滚等)
		final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
		//获取在xml中配置事务管理器
		final TransactionManager tm = determineTransactionManager(txAttr);
		if (this.reactiveAdapterRegistry != null && tm instanceof ReactiveTransactionManager) {
		   //这里好像是spring5.2以上才有的给反应式事务的入口,不用管。
			ReactiveTransactionSupport txSupport = this.transactionSupportCache.computeIfAbsent(method, key -> {
				if (KotlinDetector.isKotlinType(method.getDeclaringClass()) && KotlinDelegate.isSuspend(method)) {
					throw new TransactionUsageException(
							"Unsupported annotated transaction on suspending function detected: " + method +
							". Use TransactionalOperator.transactional extensions instead.");
				}
				ReactiveAdapter adapter = this.reactiveAdapterRegistry.getAdapter(method.getReturnType());
				if (adapter == null) {
					throw new IllegalStateException("Cannot apply reactive transaction to non-reactive return type: " +
							method.getReturnType());
				}
				return new ReactiveTransactionSupport(adapter);
			});
			return txSupport.invokeWithinTransaction(
					method, targetClass, invocation, txAttr, (ReactiveTransactionManager) tm);
		}
        //事务管理器类型转换
		PlatformTransactionManager ptm = asPlatformTransactionManager(tm);
		//获取目标方法全名
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(ptm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			//声明式事务,通过getTransaction and commit/rollback来进行事务管理
			//根据传播行为等,创建事务信息。这个后续详解
			TransactionInfo txInfo = createTransactionIfNecessary(ptm, 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 {
			   //清除事务信息,这里就是将txInfo进行重置工作,让它恢复到前一个状态。
				cleanupTransactionInfo(txInfo);
			}

			if (retVal != null && 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 {
			Object result;
			final ThrowableHolder throwableHolder = new ThrowableHolder();

			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				result = ((CallbackPreferringPlatformTransactionManager) ptm).execute(txAttr, status -> {
					TransactionInfo txInfo = prepareTransactionInfo(ptm, txAttr, joinpointIdentification, status);
					try {
						Object retVal = invocation.proceedWithInvocation();
						if (retVal != null && 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);
					}
				});
			}
			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;
			}

			// Check result state: It might indicate a Throwable to rethrow.
			if (throwableHolder.throwable != null) {
				throw throwableHolder.throwable;
			}
			return result;
		}
	}

4.3 TransactionInfo对象的详解和创建TransactionAspectSupportcreateTransactionIfNecessary()

TransactionInfo是一个链表结构,保存这本次事务的事务管理器、事务属性、事务状态,以及上一个事务的相关信息。

protected static final class TransactionInfo {
		private final PlatformTransactionManager transactionManager;
		private final TransactionAttribute transactionAttribute;
		private final String joinpointIdentification;
		private TransactionStatus transactionStatus;
		private TransactionInfo oldTransactionInfo;
		}
protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,
			@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {

		// 如果没有设置事务属性的命名,那么搞个装饰类,设置当前方法全名称为其名称
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {
					return joinpointIdentification;
				}
			};
		}

		TransactionStatus status = null;
		if (txAttr != null) {
			if (tm != null) {
		        //从事务管理器里拿到事务状态对象,见4.4节
				status = tm.getTransaction(txAttr);
			}
			else {
				if (logger.isDebugEnabled()) {
					logger.debug("Skipping transactional joinpoint [" + joinpointIdentification +
							"] because no transaction manager has been configured");
				}
			}
		}
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}

4.4 AbstractPlatformTransactionManager.getTransaction()

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)
			throws TransactionException {

		// Use defaults if no transaction definition given.
		TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());
        //1.拿到一个事务对象,会从ThreadLocal里面拿到当前的事务(包括数据库连接)
		Object transaction = doGetTransaction();
		boolean debugEnabled = logger.isDebugEnabled();
      
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			//2.如果之前已经有事物的处理逻辑
			return handleExistingTransaction(def, transaction, debugEnabled);
		}

		// Check definition settings for new transaction.
		if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout());
		}
        //下面的逻辑:就是根据不同的传播行为,确认之前没有事务情况的相应处理
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
		    //PROPAGATION_MANDATORY 传播行为:存在则加入,不存在则报错
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
				//PROPAGATION_REQUIRED :存在则加入,不存在则新建
				//PROPAGATION_REQUIRES_NEW :存在挂起创建新,不存在创建新
				//PROPAGATION_NESTED:存在嵌套,不存在创建新
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def);
			}
			try {
				return startTransaction(def, transaction, debugEnabled, suspendedResources);
			}
			catch (RuntimeException | Error ex) {
				resume(null, suspendedResources);
				throw ex;
			}
		}
		else {
		   //如果不需要事务的话,就走这里。创建一个空事务。
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + def);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);
		}
	}

4.3 事务状态对象的创建

看不下去了,参见其他大佬的博客:源码详解

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值