TransactionAspectSupport 源码解析

前言

上一篇文章我们说了AbstractPlatformTransactionManager这个类,我们通过这个类实现了,根据事物属性开始事物,和根据事物状态提交事物,回滚事物,也就是事物的基本操作,提供了PlatformTransactionManager的实现
(ps : 上一篇文章,有人回复我,好开心呀,啦啦啦啦,这次的文章有疑惑也欢迎回复,我知道的都说!)

PlatformTransactionManager

功能分析 为什么

现在问题来了,我们每次写事物相关的操作,难道每次都要我们自己开启事物,然后在异常的时候自己回滚,正常时候在手动提交,这个就和jdbc一样,相同的代码,重复操作,如果是spring只实现到这一步,肯定就不是spring,因为他不是完整的生态,只是一个基础功能,所以spring肯定要给我们做进一步封装,封装为一个模板,我们只需要传入我们方法,在给你相关这个方法所有的事物属性,和事物管理器,剩下的我不管,至于什么时候开启,什么时候提交,什么时候回滚,正常来就行,最好还给我提供一下注册方法,事物状态变化时,比如提交的时候,你可以回调我。(ps:看了这么多源码,所谓的注册,好多都是建一个xxxxregister的类,里面包含一个或者多个集合,在提供循环依次调用集合中对象的指定方法,然后在子类的特定时间,调用这个方法,这个实现就是注册对象,然后在响应时刻触发指定方法)这样就完美了!我们看看这个我们要的这个类要做什么,拿到这个方法然后做一下操作

  1. 获取这个方法的事物配置,如果有的话
  2. 获取当前所用的事物管理mannage
  3. 完整的事物执行模板,就是包装方法的执行,并在合适的时候,开启或者提交回滚事物

从这个流程上看,我们可以看出,现在我们要一个method对应一个事物,那么transactionAttribute已经不可以满足我了,因为现在method现在和manage有关联关系。我们想想还要以下属性:

  1. 所属的PlatformTransactionManager
  2. 事物对应的事物属性transactionAttribute
  3. 给PlatformTransactionManager操作的事物状态transactionStatus
  4. 事物之间都是切换和包含关系的,所以有对应上一方法的 方法事物对象

好消息,天大好消息,spring居然给我们写好了,直接用就可以,不过他是TransactionAspectSupport不是TransactionSupport,多了一层切面的含义,也决定了这个类,是为了,子类通过aop方式更加灵活的实现事物封装做准备。下面上源码,看我们说的spring都做到了吗?

源码解析

public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean

抽象的,并且实现了BeanFactoryAware,和InitializingBean

  1. 抽象的,但是他本身没有任何没有实现的方法,所以他的类名没有抽象,但是因为他是为了做切面,所以必须要子类序列化,不然不可以用,所以是抽象的
  2. 实现了BeanFactoryAware 应为他支持使用spring中的bean,做配置
  3. 实现了InitializingBean ,bean实例化后调用,做初始化检查,看看这个对象是否完整可用

然后直接以我们说的事物对象来看看他的另一个重要类 TransactionInfo,就是spring对我们说的事物对象的实现,除了包含我们的说的以外,还包含一个字段叫joinpointIdentification,这个是因为这个类是为了 供子类切面使用的,所以有一个joinpointIdentification,连接点标识。

protected final class TransactionInfo {
		
		private final PlatformTransactionManager transactionManager;

		private final TransactionAttribute transactionAttribute;

		private final String joinpointIdentification;

		private TransactionStatus transactionStatus;

		private TransactionInfo oldTransactionInfo;

初始化和处理流程

然后我们按照我们说明的流程一步步来。
流程:
封装为一个模板,我们只需要传入我们方法,他会自己判断是否有配置事物属性,再通过事物属性判断是所属哪一个事务管理PlatformTransactionManager(可能多数据源),都找到了,在用属性和事物管理器开启事物,正常执行完提交,异常自动回归,在做一些钩子事件方法,在出现提交或者回滚的时候,触发我们注册的方法

初始化

初始化的作用要让一个对象可用,所以他肯定要完成以下几个对象的填装,我们在afterPropertiesSet完成检查,用InitializingBean实现初始化后检查如下:

	// 检查实例化后必填属性是否都有
	public void afterPropertiesSet() {
		
		if (getTransactionManager() == null && this.beanFactory == null) {
			throw new IllegalStateException(
					"Setting the property 'transactionManager' or running in a BeanFactory is required");
		}
		if (this.transactionAttributeSource == null) {
			throw new IllegalStateException(
					"Either 'transactionAttributeSource' or 'transactionAttributes' is required: " +
					"If there are no transactional methods, then don't use a transaction aspect.");
		}
	}

从上面可以看出主要检查一下几个属性,是否都有:

  1. transactionAttributeSource 事物属性源,我们所有的method对应的事物配置都在这里
  2. transactionManager 我们执行的方法要使用的transactionManager
  3. beanFactory 从spring中找到配置

如果这些都有值的话,那么就完成了我们的这个类基本功能的所有属性要求,就可以使用了。

执行流程

执行流程主要看invokeWithinTransaction方法,这个方法子类提供的放入method的执行入口。源码解析如下

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

		// If the transaction attribute is null, the method is non-transactional.
		//1) 根据传入的方法和类从我们配置的事物属性源中获取事物属性,这些事物属性是配置里配置的好的,在setTransactionAttributes(Properties transactionAttributes) 中
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		//2)根据获取到的事物属性来决定使用哪一个PlatformTransactionManager,事物管理器
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		// 3) 获取这个方法的标识,一般就是 类.方法名,给子类切面用
		final String joinpointIdentification = methodIdentification(method, targetClass);
		//4)写好的事物执行模板
		//如果不是CallbackPreferringPlatformTransactionManager类型的事物管理器,或事物属性为空
		// 1.声明式事务,每次需要通过方法来获取事物属性,在判断需不需要开启事物
		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			// 定义一个具体事物
			TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
			Object retVal = null;
			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);
			return retVal;
		}
		// 2.编程式事务
		else {
			// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
			try {
				Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr,
						new TransactionCallback<Object>() {
							@Override
							public Object doInTransaction(TransactionStatus status) {
								TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
								try {
									return invocation.proceedWithInvocation();
								}
								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.
										return new ThrowableHolder(ex);
									}
								}
								finally {
									cleanupTransactionInfo(txInfo);
								}
							}
						});

				// Check result: It might indicate a Throwable to rethrow.
				if (result instanceof ThrowableHolder) {
					throw ((ThrowableHolder) result).getThrowable();
				}
				else {
					return result;
				}
			}
			catch (ThrowableHolderException ex) {
				throw ex.getCause();
			}
		}
	}

总的来看就是我们说的几步

  1. 根据传入的方法和类从我们配置的事物属性源中获取事物属性,这些事物属性是配置里配置的好的,在setTransactionAttributes(Properties transactionAttributes) 中
  2. 根据获取到的事物属性来决定使用哪一个PlatformTransactionManager,事物管理器
  3. 获取这个方法的标识,一般就是 类.方法名,给子类切面用
  4. 写好的事物执行模板,用于调用开启,或者提交又或者异常回滚

其实到这里TransactionAspectSupport 他的主要功能和含义已经说完了,剩下的就是和切面相关的,我会有专门的文章后面说核心点就是
methodInvokecation 和 methodInterceptor

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