1. 程式人生 > >spring事物--04原始碼分析-事務處理攔截器的實現分析

spring事物--04原始碼分析-事務處理攔截器的實現分析

事務處理攔截器的實現分析

通過上面的分析,很明確spring在事務方面aop是怎麼玩的了。那麼真正要處理事務是ProxyFactory.getObject() 方法返回的代理物件,通過呼叫代理物件的方法時,攔截器有一個invoker() 方法會被回撥(aop的玩法)。

TransactionInterceptor.invoke() 方法原始碼:

public Object invoke(final 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.
	//得到代理物件的目標物件,並將事務屬性傳遞給目標物件
	Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null);

	// Adapt to TransactionAspectSupport's invokeWithinTransaction...
	//呼叫父類TransactionAspectSupport的方法
	return invokeWithinTransaction(invocation.getMethod(), targetClass, invocation::proceed);
}

@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
		final InvocationCallback invocation) throws Throwable {
		
	
	// If the transaction attribute is null, the method is non-transactional.
	TransactionAttributeSource tas = getTransactionAttributeSource();
	
	//獲取事務配屬性
	final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
	
	//根據TransactionProxyFactoryBean 的配置資訊,獲取事務處理器
	final PlatformTransactionManager tm = determineTransactionManager(txAttr);
	
	//方法全限定名,如:com.masz.springtest.transaction.TransactionTXNameSpaceTest.add
	final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

	/**
	*	區分不同型別的PlatformTransactionManager,因為它們的呼叫方式不同
	*	CallbackPreferringPlatformTransactionManager 需要回調函式來實現事務的建立和提交,
	*	對於其它的事務管理器,如 DataSourceTransactionManager 就不需要通過回撥的方式來使用
	*
	*/
	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// Standard transaction demarcation with getTransaction and commit/rollback calls.
		//使用標準事務處理
		/**
		* 建立事務,把建立事務過程中得到的資訊放到TransactionInfo中去。
		*/
		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 {
			//把與執行緒繫結的TransactionInfo 設定為OldTransationInfo
			cleanupTransactionInfo(txInfo);
		}
		//通過事務處理器提交事務
		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 {
					return invocation.proceedWithInvocation();
				}
				catch (Throwable ex) {
					if (txAttr.rollbackOn(ex)) {
						// A RuntimeException: will lead to a rollback.
						// RuntimeException 會導致事務回滾
						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 {
					//把與執行緒繫結的TransactionInfo 設定為OldTransationInfo
					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;
		}
	}
}

這裡就到目標方法的呼叫和事務的提交了,和程式設計式事模板一樣。
不同的是宣告式事務基本不可見,由spring統一管理。前面說明了spring對aop事務的封裝,
下來說明spring 是如何提供宣告式事務處理的,spring封裝了什麼。

待續:spring 是如何提供宣告式事務處理的,spring封裝了什麼。