Spring聲明式事務源碼全鏈路剖析與設計模式深度解讀


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());}}
}

解讀:

  • 默認只對RuntimeExceptionError回滾。
  • rollbackFor/noRollbackFor優先處理。

三、所有事務傳播場景全鏈路源碼跟蹤

3.1 場景舉例(REQUIRES_NEW)

假設A方法有事務,B方法@Transactional(propagation = REQUIRES_NEW),A調用B:

  1. 進入B代理
  2. TransactionInterceptor#invoke
  3. createTransactionIfNecessary -> getTransaction
  4. 發現已有事務,handleExistingTransaction
  5. 判斷為REQUIRES_NEW,suspend掛起A的事務
  6. startTransaction新建B的事務
  7. 執行B
  8. B事務commit/rollback
  9. 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源碼!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/84610.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/84610.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/84610.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

云原生安全基礎:深入探討容器化環境中的權限隔離與加固策略

&#x1f525;「炎碼工坊」技術彈藥已裝填&#xff01; 點擊關注 → 解鎖工業級干貨【工具實測|項目避坑|源碼燃燒指南】 在云原生環境中&#xff0c;容器化技術&#xff08;如 Docker 和 Kubernetes&#xff09;的廣泛應用帶來了靈活性與效率&#xff0c;但也引入了新的安全挑…

如何在 ONLYOFFICE 演示文稿中調整段落首行縮進

在制作演示文稿時&#xff0c;保持內容的一致性與可讀性至關重要&#xff0c;而段落首行縮進作為格式設置的關鍵環節&#xff0c;直接影響著整體呈現效果。在本文中&#xff0c;我們將介紹如何通過創建 ONLYOFFICE 宏&#xff0c;快速設置演示文稿中所有段落的首行縮進。 關于 …

[Asp.Net]GridView、Repeater 導出Excel長數字顯示成科學計數

類似身份證純數字的格式時 &#xff0c;excel默認是數字格式 變成了科學計數法 &#xff0c; GridView:RowDataBound 添加e.Row.Cells[2].Attributes.Add(“style”, “vnd.ms-excel.numberformat:;”); protected void GridView1_RowDataBound(object sender, GridViewRowE…

Ntfs!NtfsReadBootSector函數分析之nt!CcGetVacbMiss中得到一個nt!_VACB結構

第一部分&#xff1a; 1: kd> g Breakpoint 3 hit nt!CcGetVacbMiss: 80a1a19e 6a30 push 30h 1: kd> kc # 00 nt!CcGetVacbMiss 01 nt!CcGetVirtualAddress 02 nt!CcMapData 03 Ntfs!NtfsMapStream 04 Ntfs!NtfsReadBootSector Ntfs…

Linux10正式版發布,擁抱AI了!

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 作者&#xff1a;IT邦德 中國DBA聯盟(ACDU)成員&#xff0c;10余年DBA工作經驗 Oracle、PostgreSQL ACE CSDN博客專家及B站知名UP主&#xff0c;全網粉絲10萬 擅長主流Oracle、MySQL、PG、高斯…

關于 SSE(Server-Sent Events)過程的簡要解剖

Js前端&#xff1a;發送普通請求 fetch(...) .then(()>{}) .catch(()>{})Java后端&#xff1a;接收請求后調用請求處理函數&#xff0c;函數返回一個emiiter對象 public SseEmitter handleRequest(...) {// 創建一個 SseEmitter 對象&#xff0c;用于發送 SSE 事件SseE…

PyTorch 中unsqueeze(-1)用法

unsqueeze(-1) 是 PyTorch 中的一個張量操作&#xff0c;用于?在指定維度上增加一個長度為1的維度?&#xff08;即擴展維度&#xff09;。具體解析如下&#xff1a; 功能說明 ?作用位置? -1 表示在張量的?最后一個維度?后添加新維度。 &#xff08;等價于 dimlen(tensor.…

RTC技術

什么是RTC RTC&#xff08;Real time communication&#xff09;實時通信&#xff0c;是實時音視頻的一個簡稱&#xff0c;我們常說的RTC技術一般指的是WebRTC技術&#xff0c;已經被 W3C 和 IETF 發布為正式標準。由于幾乎所有主流瀏覽器都支持 WebRTC 標準 API &#xff0c;…

vue+cesium示例:3Dtiles三維模型高度調整(附源碼下載)

接到一位知識星友的邀請&#xff0c;實現他需要3Dtiles三維模型的簡單高度調整需求&#xff0c;適合學習Cesium與前端框架結合開發3D可視化項目。 demo源碼運行環境以及配置 運行環境&#xff1a;依賴Node安裝環境&#xff0c;demo本地Node版本:推薦v18。 運行工具&#xff1a;…

詳解3DGS

4 可微分的3D高斯 splatting 核心目標與表示選擇 我們的目標是從無法線的稀疏SfM點出發&#xff0c;優化出一種能夠實現高質量新視角合成的場景表示。為此&#xff0c;我們選擇3D高斯作為基本圖元&#xff0c;它兼具可微分的體表示特性和非結構化的顯式表示優勢&#xff0c;既…

構建版本沒mac上傳APP方法

在蘋果開發者的app store connect上架Ios應用的時候&#xff0c;發現需要使用xode等軟件來上傳iOS的APP。 但是不管是xcode也好&#xff0c;transporter也好&#xff0c;還是命令行工具也好&#xff0c;都必須安裝在mac電腦才能使用&#xff0c;。 假如沒有mac電腦&#xff0…

Gitee PPM:智能化項目管理如何重塑軟件工廠的未來格局

在數字化轉型浪潮席卷全球的當下&#xff0c;軟件開發行業正經歷著前所未有的變革。隨著企業項目復雜度呈指數級增長&#xff0c;傳統項目管理方式已難以應對多項目并行、跨團隊協作等挑戰。Gitee項目組合管理&#xff08;PPM&#xff09;作為新一代智能化項目管理解決方案&…

node入門:安裝和npm使用

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、安裝npm命令nvm 前言 因為學習vue接觸的&#xff0c;一直以為node是和vue綁定的&#xff0c;還以為vue跑起來必須要node&#xff0c;后續發現并不是。 看…

單例模式,餓漢式,懶漢式,在java和spring中的體現

目錄 餓漢式單例模式 懶漢式單例模式 Spring中的單例模式 關鍵差異對比 在Java和Spring中的應用場景 手寫案例 單例模式是一種創建型設計模式&#xff0c;其核心在于確保一個類僅有一個實例&#xff0c;并提供一個全局訪問點來獲取該實例。下面將詳細介紹餓漢式和懶漢式…

網絡編程——UDP網絡編程

文章目錄 1、sendto()&#xff0c;recvfrom() 與TCP編程不同的是&#xff1a; 無需建立連接&#xff0c;在recvfrom()阻塞等待客戶端的數據&#xff0c;收到數據后進入do something進行數據的處理。 1、sendto()&#xff0c;recvfrom() ssize_t sendto(int socket, void *mes…

OpenSSL詳解

這里寫目錄標題 選項&#xff1a;**通用選項&#xff1a;**1. genrsa&#xff1a;生成RSA密鑰對3. req&#xff1a;生成證書簽名請求4. x509&#xff1a;生成自簽名證書 **證書管理&#xff1a;**1. verify&#xff1a;驗證證書2. x509&#xff1a;查看證書詳情3. crl&#xff…

MySQL的日志和備份

目錄 一. MySQL的日志 1.1 日志的作用 1.2 日志的分類 1.3 事務日志 1.4 錯誤日志 1.5 通用日志 1.6 慢查詢日志 1.7 二進制備份 二. 備份 2.1 數據備份的重要性 2.2 備份的分類 2.3 MySQL備份的內容 2.4 備份的注意點 2.5 備份的工具 2.6 實戰案例 2.7 mysql…

前端性能優化:如何讓網頁加載更快?

摘要 想象一下&#xff0c;滿心期待點開一個網頁&#xff0c;卻等了十幾秒還卡在加載界面&#xff0c;你是不是瞬間就想關掉走人&#xff1f;這可不是個別用戶的 “急性子”&#xff0c;數據顯示&#xff0c;網頁每多延遲 1 秒&#xff0c;用戶流失率可能增加 11%&#xff01;…

[論文閱讀]Prompt Injection attack against LLM-integrated Applications

Prompt Injection attack against LLM-integrated Applications [2306.05499] Prompt Injection attack against LLM-integrated Applications 傳統提示注入攻擊效果差&#xff0c;主要原因在于&#xff1a; 不同的應用對待用戶的輸入內容不同&#xff0c;有的將其視為問題&a…

微信小程序進階第2篇__事件類型_冒泡_非冒泡

在小程序中&#xff0c; 事件分為兩種類型&#xff1a; 冒泡事件&#xff0c; 當一個組件上的事件被觸發后&#xff0c;該事件會向父節點傳遞非冒泡事件&#xff0c; 當一個組件上的事件被觸發后&#xff0c; 該事件不會向父節點傳遞。 一 冒泡事件 tap&#xff0c; touchst…