在spring源碼系列9:事務代理的建立一節, 事務經過定義java
在spring源碼系列10:AOP代理對象的執行一節。 總結出,無論是AOP-JDK代理仍是CGLB動態代理,都會執行Advice完成加強功能。spring
也就是說:事務的核心功能就在這個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()
去執行緩存
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;
}
...
}
複製代碼
咱們使用註解@Transactional時,註解元信息會被包裝成TransactionAttribute ,此處拿到的就是@Transactional的元數據ide
找到一個合適的事務管理器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
獲取目標方法全名spa
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 ()是一個模板方法,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(處理當前有事務的狀況) 事務的傳播屬性處理
suspend(transaction)
掛起在代碼裏的表現是:(1)將當前是個人ConnectionHolder設置爲null(2)從ThreadLocal對象resources中移除當前線程的Connection(3)將事務的掛起狀態封裝到SuspendedResourcesHolder中設置到TransactionStatus中,返回。suspend(transaction)
掛起,doBegin(transaction, definition)
建立新事務;doBegin(transaction, definition)
建立新事務4.1.4: 校驗超時
4.1.5:處理當前沒有事務的狀況
doBegin(transaction, definition)
事務建立 doBegin
至此:getTransaction 返回一個封裝了事務的TransactionStatus對象。 總結下:getTransaction 方法重要點:
prepareTransactionInfo方法主要是封裝:事務管理器PlatformTransactionManager
對象,TransactionAttribute
事務屬性對象,方法名joinpointIdentification
,TransactionStatus
對象 成一TransactionInfo
對象。並把TransactionInfo
對象經過bindToThread()
方法綁定到ThreadLocal<TransactionInfo> transactionInfoHolder
。
至此: createTransactionIfNecessary完成,獲得一個TransactionInfo對象。
執行下一個加強。在沒其餘加強的狀況下,這一般會致使調用目標對象。
在目標方法執行錯誤的狀況下,catch異常,執行回滾。 核心在DataSourceTransactionManager.doRollback方法
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
}
try {
con.rollback();
}
複製代碼
finally 必定執行,清除事務信息。 其實就是把ThreadLocal transactionInfoHolder裏的新事務信息清除掉。設置爲原事務信息
提交事務 核心在DataSourceTransactionManager.doCommit方法
Connection con = txObject.getConnectionHolder().getConnection();
if (status.isDebug()) {
logger.debug("Committing JDBC transaction on Connection [" + con + "]");
}
try {
con.commit();
}
複製代碼
至此整個事務執行原理完成。裏面涉及到不少細節,因爲篇幅的緣由不能一一列出。建議多看代碼。
事務代理的執行,其實就是在AOP基礎上的創建起來的。
關鍵是理解TransactionInterceptor(Advice)。在目標方法執行先後對其進行事務控制的加強。