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

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