Spring聲明式事務源碼全鏈路剖析與設計模式深度解讀
作者:AI
日期:2025-05-22
一、前言
Spring事務是企業級開發的基石,但“為什么有時事務失效?”、“不同傳播行為背后發生了什么?”、“Spring事務源碼到底如何實現?”這些問題困擾著無數開發者。本文將從源碼行級剖析、事務傳播機制全鏈路跟蹤、設計模式變體實現三個層面,徹底解構Spring聲明式事務體系。
二、Spring聲明式事務核心源碼全鏈路
2.1 事務AOP代理的生成(代理模式)
Spring通過AOP機制實現聲明式事務,核心邏輯在于Bean初始化時判斷是否需要代理,并生成代理對象。
源碼片段:AbstractAutoProxyCreator#wrapIfNecessary
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// ...是否需要事務增強判斷...Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));return proxy;
}
解讀:
- 滿足條件即生成JDK/CGLIB代理,后續所有對該Bean的調用都會被代理攔截。
- 這就是經典的代理模式應用。
2.2 進入AOP攔截鏈(責任鏈模式)
代理對象的方法調用被攔截后,會進入AOP攔截器鏈,事務攔截器只是其中之一。
源碼片段:CglibAopProxy.DynamicAdvisedInterceptor#intercept
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);if (chain.isEmpty()) {return methodProxy.invoke(target, args);} else {return new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();}
}
解讀:
- 多個攔截器順序執行,責任鏈模式的典范。
TransactionInterceptor
在鏈中負責事務處理。
2.3 事務攔截器主流程(模板方法+責任鏈)
源碼片段:TransactionInterceptor#invoke
public Object invoke(final MethodInvocation invocation) throws Throwable {TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass);PlatformTransactionManager tm = determineTransactionManager(txAttr);String joinpointIdentification = methodIdentification(method, targetClass, txAttr);TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);Object retVal;try {retVal = invocation.proceedWithInvocation();} catch (Throwable ex) {completeTransactionAfterThrowing(txInfo, ex);throw ex;} finally {cleanupTransactionInfo(txInfo);}commitTransactionAfterReturning(txInfo);return retVal;
}
解讀:
- 事務的開啟、提交、回滾、清理均在此流程完成,標準的模板方法模式。
- 業務代碼通過
proceedWithInvocation()
繼續責任鏈。
2.4 事務管理器與策略模式
源碼片段:TransactionAspectSupport#createTransactionIfNecessary
protected TransactionInfo createTransactionIfNecessary(PlatformTransactionManager tm, TransactionAttribute txAttr, String joinpointIdentification) {if (txAttr != null && tm != null) {TransactionStatus status = tm.getTransaction(txAttr);return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);}// ...
}
解讀:
PlatformTransactionManager
是策略接口,支持多種實現(JDBC、JPA、JTA等)。- 運行時根據配置選擇合適的策略。
2.5 事務傳播機制源碼全鏈路
傳播行為決策入口
源碼片段:AbstractPlatformTransactionManager#getTransaction
public final TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {Object transaction = doGetTransaction(); // 線程級事務資源if (isExistingTransaction(transaction)) {return handleExistingTransaction(definition, transaction, debugEnabled);}// ...無事務的處理...
}
核心傳播分支源碼
源碼片段:handleExistingTransaction
(部分)
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW) {Object suspendedResources = suspend(transaction);try {return startTransaction(definition, transaction, debugEnabled, suspendedResources);} catch (RuntimeException | Error beginEx) {resumeAfterBeginException(transaction, suspendedResources, beginEx);throw beginEx;}
}
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {DefaultTransactionStatus status = prepareTransactionStatus(...);status.createAndHoldSavepoint();return status;
}
// ...其它分支...
解讀:
- REQUIRES_NEW:掛起原事務、新建事務。
- NESTED:創建JDBC保存點,支持嵌套回滾。
- 其它傳播行為:詳見下表。
2.6 各傳播行為源碼鏈路與執行表
傳播類型 | 現有事務 | 行為 | 源碼分支位置 |
---|---|---|---|
REQUIRED | 有 | 加入現有事務 | handleExistingTransaction 默認分支 |
無 | 創建新事務 | getTransaction, startTransaction | |
REQUIRES_NEW | 有 | 掛起原事務,創建新事務 | handleExistingTransaction, suspend |
無 | 創建新事務 | getTransaction, startTransaction | |
SUPPORTS | 有 | 加入現有事務 | handleExistingTransaction 默認分支 |
無 | 非事務性執行 | getTransaction, prepareTransactionStatus | |
NOT_SUPPORTED | 有 | 掛起原事務,非事務性執行 | handleExistingTransaction, suspend |
無 | 非事務性執行 | getTransaction, prepareTransactionStatus | |
NEVER | 有 | 拋異常 | handleExistingTransaction, throw |
無 | 非事務性執行 | getTransaction, prepareTransactionStatus | |
MANDATORY | 有 | 加入現有事務 | handleExistingTransaction 默認分支 |
無 | 拋異常 | getTransaction, throw | |
NESTED | 有 | 創建保存點,嵌套事務 | handleExistingTransaction, createAndHoldSavepoint |
無 | 創建新事務 | getTransaction, startTransaction |
2.7 事務掛起、恢復與保存點(進階細節)
源碼片段:掛起/恢復/保存點
protected final SuspendedResourcesHolder suspend(@Nullable Object transaction) {if (transaction != null) {doSuspend(transaction); // 釋放當前事務資源}List<TransactionSynchronization> suspendedSynchronizations = doSuspendSynchronization();// 返回SuspendedResourcesHolder
}protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder) {if (resourcesHolder != null) {doResume(transaction, resourcesHolder.suspendedResources);}doResumeSynchronization(resourcesHolder.suspendedSynchronizations);
}DefaultTransactionStatus status = prepareTransactionStatus(...);
status.createAndHoldSavepoint(); // JDBC Savepoint
解讀:
- 掛起/恢復用于REQUIRES_NEW、NOT_SUPPORTED等。
- NESTED通過保存點實現內層回滾而不影響外層。
2.8 事務提交/回滾與異常判定
源碼片段:事務回滾判定/提交
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.getTransactionStatus() != null) {if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());} else {txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}}
}
解讀:
- 默認只對
RuntimeException
和Error
回滾。 rollbackFor
/noRollbackFor
優先處理。
三、所有事務傳播場景全鏈路源碼跟蹤
3.1 場景舉例(REQUIRES_NEW)
假設A方法有事務,B方法@Transactional(propagation = REQUIRES_NEW)
,A調用B:
- 進入B代理
TransactionInterceptor#invoke
createTransactionIfNecessary
->getTransaction
- 發現已有事務,
handleExistingTransaction
- 判斷為REQUIRES_NEW,
suspend
掛起A的事務 startTransaction
新建B的事務- 執行B
- B事務
commit
/rollback
resume
恢復A的事務
其他傳播行為可類推,詳見上表。
四、設計模式在Spring事務中的變體實現
- 代理模式:AOP代理對象生成與調用攔截
- 策略模式:
PlatformTransactionManager
多實現切換 - 模板方法模式:
AbstractPlatformTransactionManager
定義流程,子類實現細節 - 責任鏈模式:AOP攔截器鏈,事務攔截器只是其中一環
- 適配器模式:JDBC、JPA、JTA等適配到統一事務接口
- 裝飾器/觀察者變體:
TransactionSynchronizationManager
擴展事務回調
五、常見誤區與源碼分析
5.1 內部方法調用事務失效
@Service
public class A {@Transactionalpublic void methodA() { methodB(); }@Transactionalpublic void methodB() { /* ... */ }
}
分析:
methodB()
為內部調用,未經過AOP代理,不會增強事務。
解決方案:
- 通過外部Bean注入調用或自我注入。
六、實用速查與小結
- 代理橫切事務,策略適配場景,模板規范流程,責任鏈環環相扣,適配器統一接口。
- 傳播行為定范圍,異常回滾看類型,自定義優先于默認。
- 源碼每一行都映射著設計思想,理解源碼才能知其所以然。
七、參考資料
- Spring事務源碼官方GitHub
- Spring官方事務文檔
- Spring源碼深度解析
八、結語
Spring事務的本質,是AOP+多設計模式聯合作用的工程藝術。理解每一行源碼,追蹤每一個傳播行為的全鏈路,能讓你真正掌控事務邊界與一致性。
知其然,更知其所以然。
歡迎收藏、點贊、轉發,有問題歡迎評論區一起深挖Spring源碼!