spring源碼系列11:事務代理對象的執行

回顧

spring源碼系列9:事務代理的建立一節, 事務經過定義java

  • 切點: TransactionAttributeSourcePointcut 、
  • 通知(攔截器) TransactionInterceptor
  • Advisor: BeanFactoryTransactionAttributeSourceAdvisor
    在AOP基礎上實現事務代理的功能

spring源碼系列10:AOP代理對象的執行一節。 總結出,無論是AOP-JDK代理仍是CGLB動態代理,都會執行Advice完成加強功能。spring

也就是說:事務的核心功能就在這個TransactionInterceptor數據庫

事務執行

TransactionInterceptor

@Override
	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...
		return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
			@Override
			public Object proceedWithInvocation() throws Throwable {
				return invocation.proceed();
			}
		});
	}
複製代碼

交給父類TransactionAspectSupport.invokeWithinTransaction()去執行緩存

TransactionAspectSupport

invokeWithinTransaction方法比較長,咱們看前半部分。app

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

		// If the transaction attribute is null, the method is non-transactional.
		1.
		final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
		2.
		final PlatformTransactionManager tm = determineTransactionManager(txAttr);
		3.
		final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);

		if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
			// Standard transaction demarcation with getTransaction and commit/rollback calls.
			4.
			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.
				5.
				retVal = invocation.proceedWithInvocation();
			}
			catch (Throwable ex) {
				// target invocation exception
				6.
				completeTransactionAfterThrowing(txInfo, ex);
				throw ex;
			}
			finally {
			7.
				cleanupTransactionInfo(txInfo);
			}
			8.
			commitTransactionAfterReturning(txInfo);
			return retVal;
		}
		... 
	}
複製代碼

1.拿到事務屬性TransactionAttribute :

咱們使用註解@Transactional時,註解元信息會被包裝成TransactionAttribute ,此處拿到的就是@Transactional的元數據ide

2.determineTransactionManager(txAttr)

找到一個合適的事務管理器post

protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) {
		// Do not attempt to lookup tx manager if no tx attributes are set
		//未設置事務屬性,也沒有設置beanFactory ,直接返回
		if (txAttr == null || this.beanFactory == null) {
			return getTransactionManager();
		}
		//若是@Transactional 指定了具體事務管理器,則根據beanname去容器中找到他
		String qualifier = txAttr.getQualifier();
		if (StringUtils.hasText(qualifier)) {
			return determineQualifiedTransactionManager(qualifier);
		}
		//若是是TransactionAspectSupport.transactionManagerBeanName指定了具體事務管理器,
		//beanname去容器中找
		else if (StringUtils.hasText(this.transactionManagerBeanName)) {
			return determineQualifiedTransactionManager(this.transactionManagerBeanName);
		}
		//沒有beanName指定具體的事務管理器Bean。
		/** 1.查看transactionManager屬性是否設置事務管理器對象 2.查看事務管理器緩存中有沒有 3.去容器中尋找,找PlatformTransactionManager接口的實現類。getBean(PlatformTransactionManager), 找到放到事務管理器緩存中。 **/
		else {
			PlatformTransactionManager defaultTransactionManager = getTransactionManager();
			if (defaultTransactionManager == null) {
				defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
				if (defaultTransactionManager == null) {
					defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
					this.transactionManagerCache.putIfAbsent(
							DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
				}
			}
			return defaultTransactionManager;
		}
	}
複製代碼

以集成了DataSourceTransactionManager爲例。determineTransactionManager返回的就是DataSourceTransactionManager對象。this

3.methodIdentification方法

獲取目標方法全名spa

4.createTransactionIfNecessary開啓事務重點

protected TransactionInfo createTransactionIfNecessary( PlatformTransactionManager tm, TransactionAttribute txAttr, final String joinpointIdentification) {
		// If no name specified, apply method identification as transaction name.
		若是事務名稱沒有指定,則使用方法名做爲事務名
		if (txAttr != null && txAttr.getName() == null) {
			txAttr = new DelegatingTransactionAttribute(txAttr) {
				@Override
				public String getName() {return joinpointIdentification;}
			};
		}
		...
		TransactionStatus status = tm.getTransaction(txAttr);
		...
		return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
	}
複製代碼

重點在線程

  • getTransaction方法獲取TransactionStatus 事務
  • prepareTransactionInfo方法上,封裝一個TransactionInfo
4.1:getTransaction ()

getTransaction ()是一個模板方法,PlatformTransactionManager定義了getTransaction 方法。抽象類AbstractPlatformTransactionManager實現了getTransaction 方法。由於是模板方法。方法內不少方法都是在具體的PlatformTransactionManager實現的。(本文以DataSourceTransactionManager爲例)

public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
		1.嘗試獲取事務對象,並封裝當前線程中以當前datasource爲key的Connection。
		Object transaction = doGetTransaction();
		2.沒有配置事務屬性,則建立一個默認的事務屬性
		if (definition == null) {
			// Use defaults if no transaction definition given.
			definition = new DefaultTransactionDefinition();
		}
		3.判斷是否有已經存在是否:判斷條件是當前線程有Connection.而且Connection是活躍的
		if (isExistingTransaction(transaction)) {
			// Existing transaction found -> check propagation behavior to find out how to behave.
			已存在事務,則處理傳播屬性,而後返回。(處理兩個事務之間的傳播屬性關係)
			return handleExistingTransaction(definition, transaction, debugEnabled);
		}
		===========當前沒有事務
		// Check definition settings for new transaction.
		4.超時時間校驗
		if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
			throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
		}
		5.開始處理當前事務
		// No existing transaction found -> check propagation behavior to find out how to proceed.
		if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
			throw new IllegalTransactionStateException(
					"No existing transaction found for transaction marked with propagation 'mandatory'");
		}
		else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
				definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
			SuspendedResourcesHolder suspendedResources = suspend(null);
			if (debugEnabled) {
				logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
			}
			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 ex) {
				resume(null, suspendedResources);
				throw ex;
			}
			catch (Error err) {
				resume(null, suspendedResources);
				throw err;
			}
		}
		else {
			// Create "empty" transaction: no actual transaction, but potentially synchronization.
			if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) {
				logger.warn("Custom isolation level specified but no actual transaction initiated; " +
						"isolation level will effectively be ignored: " + definition);
			}
			boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
			return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
		}
	}
複製代碼

下面拆解此方法


4.1.1:doGetTransaction獲取事務對象 doGetTransaction的實如今DataSourceTransactionManager中,doGetTransactiond建立一個DataSourceTransactionObject用於表示事務。並嘗試獲取一個與當前線程關聯的Connection,這一部分工做交給事務同步管理器TransactionSynchronizationManager來完成。核心在doGetResource方法上。

private static final ThreadLocal<Map<Object, Object>> resources =
			new NamedThreadLocal<Map<Object, Object>>("Transactional resources");
private static Object doGetResource(Object actualKey) {
		Map<Object, Object> map = resources.get();
		if (map == null) {
			return null;
		}
		Object value = map.get(actualKey);
		// Transparently remove ResourceHolder that was marked as void...
		if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {
			map.remove(actualKey);
			// Remove entire ThreadLocal if empty...
			if (map.isEmpty()) {
				resources.remove();
			}
			value = null;
		}
		return value;
	}
複製代碼

以當前Datasoure對象爲key ,從ThreadLocal對象resources中獲取Connection

4.1.2:沒有事務屬性建立一個事務屬性

4.1.3:判斷當前是否有事務存在(重點) 默認是false,子類能夠重寫isExistingTransaction方法。DataSourceTransactionManager中重寫了此方法

@Override
	protected boolean isExistingTransaction(Object transaction) {
		DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
		return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
	}
複製代碼

查看事務對象獲取的Connectin是否爲空,Connection是否活躍。 是否存在事務指:當前線程中是否存在以當前數據源爲key的獲取鏈接Connection. 4.1.3.1: handleExistingTransaction(處理當前有事務的狀況) 事務的傳播屬性處理

  • NEVER: 不支持當前事務,由於當前有事務,拋出異常
  • NOT_SUPPORTED:不支持當前事務,當前有事務存在,就掛起當前事務。所謂的suspend(transaction)掛起在代碼裏的表現是:(1)將當前是個人ConnectionHolder設置爲null(2)從ThreadLocal對象resources中移除當前線程的Connection(3)將事務的掛起狀態封裝到SuspendedResourcesHolder中設置到TransactionStatus中,返回。
  • REQUIRES_NEW:掛起當前事務,建立新事務。suspend(transaction)掛起,doBegin(transaction, definition)建立新事務;
  • NESTED:嵌套事務。分爲非JTA事務與JTA事務。JTA事務建立doBegin(transaction, definition)建立新事務
  • SUPPORTS/REQUIRED/MANDATORY: 不處理

4.1.4: 校驗超時

4.1.5:處理當前沒有事務的狀況

  • MANDATORY: 支持當前事務,當前事務沒有,則拋出異常
  • REQUIRED/REQUIRES_NEW/NESTED: 建立新事務doBegin(transaction, definition)
  • NOT_SUPPORTED/SUPPORTS/NEVER: 只是打印warn日誌。隔離無心義。

事務建立 doBegin

  1. 事務裏沒有數據庫鏈接Connection,則從dataSource裏獲取一個
  2. 設置隔離級別
  3. 設置數據庫自動提交爲false
  4. 把Connection放到ThreadLocal對象resources中

至此:getTransaction 返回一個封裝了事務的TransactionStatus對象。 總結下:getTransaction 方法重要點

  • 獲取數據鏈接,
  • 處理spring事務傳播方式
  • 設置自動提交爲false

4.2prepareTransactionInfo方法

prepareTransactionInfo方法主要是封裝:事務管理器PlatformTransactionManager對象,TransactionAttribute事務屬性對象,方法名joinpointIdentificationTransactionStatus對象 成一TransactionInfo對象。並把TransactionInfo對象經過bindToThread()方法綁定到ThreadLocal<TransactionInfo> transactionInfoHolder

至此: createTransactionIfNecessary完成,獲得一個TransactionInfo對象。

5.invocation.proceedWithInvocation();

執行下一個加強。在沒其餘加強的狀況下,這一般會致使調用目標對象。

6.completeTransactionAfterThrowing

在目標方法執行錯誤的狀況下,catch異常,執行回滾。 核心在DataSourceTransactionManager.doRollback方法

Connection con = txObject.getConnectionHolder().getConnection();
		if (status.isDebug()) {
			logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
		}
		try {
			con.rollback();
		}
複製代碼

7.cleanupTransactionInfo(txInfo)

finally 必定執行,清除事務信息。 其實就是把ThreadLocal transactionInfoHolder裏的新事務信息清除掉。設置爲原事務信息

8.commitTransactionAfterReturning(txInfo);

提交事務 核心在DataSourceTransactionManager.doCommit方法

Connection con = txObject.getConnectionHolder().getConnection();
		if (status.isDebug()) {
			logger.debug("Committing JDBC transaction on Connection [" + con + "]");
		}
		try {
			con.commit();
		}
複製代碼

至此整個事務執行原理完成。裏面涉及到不少細節,因爲篇幅的緣由不能一一列出。建議多看代碼。

總結

事務代理的執行,其實就是在AOP基礎上的創建起來的。

關鍵是理解TransactionInterceptor(Advice)。在目標方法執行先後對其進行事務控制的加強。

相關文章
相關標籤/搜索