Spring聲明式事務(wù)(@Transactional)通過(guò)AOP實(shí)現(xiàn)過(guò)程
Spring 的聲明式事務(wù) (@Transactional) 是 AOP 技術(shù)最經(jīng)典的應(yīng)用之一。
其核心思想是:通過(guò) AOP 代理,在業(yè)務(wù)代碼執(zhí)行前后,自動(dòng)地開(kāi)啟、提交或回滾事務(wù)。
下面是詳細(xì)的實(shí)現(xiàn)步驟和原理:
Step 1: 掃描與識(shí)別
當(dāng) Spring 容器啟動(dòng)時(shí):
- 它會(huì)掃描所有的 Bean。
- 它會(huì)尋找被
@Transactional注解標(biāo)記的類或方法。 - 一旦發(fā)現(xiàn)某個(gè) Bean(例如
OrderService)中含有@Transactional方法,Spring 就會(huì)判定這個(gè) Bean 需要事務(wù)增強(qiáng)。
Step 2: 創(chuàng)建代理對(duì)象
對(duì)于需要事務(wù)增強(qiáng)的 Bean,Spring 不會(huì)直接將原始的 OrderService 實(shí)例放入容器。相反,它會(huì):
- 使用 AOP 框架(具體來(lái)說(shuō)是
TransactionProxyFactoryBean)為這個(gè)OrderService創(chuàng)建一個(gè)代理對(duì)象(OrderServiceProxy)。 - 這個(gè)代理對(duì)象看起來(lái)和原始對(duì)象一模一樣(實(shí)現(xiàn)了相同的接口或繼承了相同的類),但它的內(nèi)部包含了額外的事務(wù)攔截器 (Transaction Interceptor)。
- 最終,當(dāng)其他組件(如 Controller)通過(guò)
@Autowired注入OrderService時(shí),它們實(shí)際得到的是這個(gè)代理對(duì)象。
Step 3: 方法調(diào)用與攔截 (核心)
當(dāng)你的代碼調(diào)用一個(gè)被 @Transactional 注解的方法時(shí)(例如 orderServiceProxy.placeOrder()),這個(gè)調(diào)用過(guò)程會(huì)遵循一個(gè)典型的環(huán)繞通知 (@Around) 流程:
調(diào)用被代理對(duì)象攔截:
你的調(diào)用首先到達(dá)的是 OrderServiceProxy,而不是原始的 OrderService。
事務(wù)攔截器 (Transaction Interceptor) 被激活:
代理對(duì)象中的事務(wù)攔截器(可以看作一個(gè)環(huán)繞通知)開(kāi)始工作。它的邏輯如下:
a. 【方法執(zhí)行前】準(zhǔn)備事務(wù)環(huán)境:
- * 獲取
PlatformTransactionManager(事務(wù)管理器,如DataSourceTransactionManager)。 - * 檢查當(dāng)前是否存在一個(gè)已激活的事務(wù)。
- * 根據(jù)
@Transactional注解中配置的傳播行為 (Propagation) 來(lái)決定下一步操作。例如: - *
REQUIRED(默認(rèn)):如果當(dāng)前沒(méi)事務(wù),就開(kāi)啟一個(gè)新事務(wù) (connection.setAutoCommit(false));如果已有事務(wù),就加入它。 - *
REQUIRES_NEW:掛起當(dāng)前事務(wù)(如果存在),并總是開(kāi)啟一個(gè)全新的事務(wù)。 - * 根據(jù)注解配置設(shè)置事務(wù)的隔離級(jí)別 (Isolation)、超時(shí)時(shí)間 (Timeout)、只讀狀態(tài) (Read-Only) 等。
b. 【調(diào)用目標(biāo)方法】執(zhí)行核心業(yè)務(wù)邏輯:
- * 在
try代碼塊中,事務(wù)攔截器會(huì)調(diào)用原始的OrderService對(duì)象的placeOrder()方法。 - *
orderRepository.save(order); - *
stockService.decreaseStock(order.getProductId()); - * 你的所有業(yè)務(wù)代碼都在這個(gè)事務(wù)的保護(hù)下執(zhí)行。
c. 【方法成功返回后】提交事務(wù):
- * 如果目標(biāo)方法成功執(zhí)行完畢,沒(méi)有拋出任何異常,
try塊正常結(jié)束。 - * 事務(wù)攔截器會(huì)捕獲到這個(gè)成功的狀態(tài),然后調(diào)用
transactionManager.commit()來(lái)提交事務(wù)。
d. 【方法拋出異常后】回滾事務(wù):
- * 如果目標(biāo)方法在執(zhí)行過(guò)程中拋出了異常,這個(gè)異常會(huì)被
catch塊捕獲。 - * 事務(wù)攔截器會(huì)檢查這個(gè)異常的類型。根據(jù)
@Transactional注解的回滾規(guī)則 (Rollback Rules): - * 默認(rèn)情況下,如果拋出的是
RuntimeException或Error,事務(wù)攔截器會(huì)調(diào)用transactionManager.rollback()來(lái)回滾事務(wù)。 - * 如果拋出的是已檢查異常 (Checked Exception),默認(rèn)不會(huì)回滾(這個(gè)行為可以配置)。
- * 回滾后,異常會(huì)繼續(xù)向上層拋出,以便調(diào)用方可以感知到錯(cuò)誤。
圖解實(shí)現(xiàn)原理
+----------------+
| Controller |
+----------------+
| 1. 調(diào)用 orderService.placeOrder()
v
+-----------------------------------------------------------------------------+
| OrderService 代理對(duì)象 (Proxy) |
| |
| +---------------------------------------------------------------------+ |
| | 事務(wù)攔截器 (Transaction Interceptor - Around Advice) | |
| | | |
| | 2. 【方法執(zhí)行前】 | |
| | - 獲取事務(wù)管理器 | |
| | - 根據(jù)傳播行為,開(kāi)啟新事務(wù) (connection.setAutoCommit(false)) | |
| | | |
| | 3. 【調(diào)用目標(biāo)方法】try { | |
| | target.placeOrder(); <---------------------------------+ | |
| | } | | |
| | | | |
| | 4a. 【成功返回后】catch (no exception) { | | |
| | transactionManager.commit(); // 提交事務(wù) | | |
| | } | | |
| | | | |
| | 4b. 【拋出異常后】catch (RuntimeException | Error) { | | |
| | transactionManager.rollback(); // 回滾事務(wù) | | |
| | throw ex; // 繼續(xù)拋出異常 | | |
| | } | | |
| | | |
| +---------------------------------------------------------------------+ |
| |
+-----------------------------------------------------------------------------+
^ |
| 5. 最終結(jié)果或異常返回給 Controller |
| |
| +--------------------------------------------------------+
| |
v v
+--------------------------+
| OrderService 目標(biāo)對(duì)象 |
| (包含純粹的業(yè)務(wù)邏輯) |
+--------------------------+
總結(jié)
- 核心技術(shù):Spring AOP 的環(huán)繞通知 (
@Around)。
關(guān)鍵角色:
- 代理對(duì)象 (Proxy):攔截方法調(diào)用。
- 事務(wù)攔截器 (Transaction Interceptor):實(shí)現(xiàn)了具體的事務(wù)管理邏輯。
- 事務(wù)管理器 (PlatformTransactionManager):執(zhí)行真正的事務(wù)操作(開(kāi)啟、提交、回滾)。
工作流程:
- 代理攔截:調(diào)用被代理對(duì)象攔截。
- 事務(wù)開(kāi)啟:在目標(biāo)方法執(zhí)行前,根據(jù)配置開(kāi)啟事務(wù)。
- 業(yè)務(wù)執(zhí)行:調(diào)用原始目標(biāo)對(duì)象的業(yè)務(wù)方法。
- 事務(wù)提交/回滾:根據(jù)業(yè)務(wù)方法的執(zhí)行結(jié)果(成功或異常),決定是提交還是回滾事務(wù)。
通過(guò)這種方式,AOP 完美地將重復(fù)、通用的事務(wù)管理代碼從核心業(yè)務(wù)邏輯中剝離出來(lái),實(shí)現(xiàn)了高度的解耦和代碼的整潔。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringCloud服務(wù)接口調(diào)用OpenFeign及使用詳解
這篇文章主要介紹了SpringCloud服務(wù)接口調(diào)用——OpenFeign,在學(xué)習(xí)Ribbon時(shí),服務(wù)間調(diào)用使用的是RestTemplate+Ribbon實(shí)現(xiàn),而Feign在此基礎(chǔ)上繼續(xù)進(jìn)行了封裝,使服務(wù)間調(diào)用變得更加方便,需要的朋友可以參考下2023-04-04
Java微服務(wù)無(wú)損發(fā)布生產(chǎn)實(shí)戰(zhàn)案例及驗(yàn)證
微服務(wù)架構(gòu)是一項(xiàng)在云中部署應(yīng)用和服務(wù)的新技術(shù),這篇文章主要介紹了Java微服務(wù)無(wú)損發(fā)布生產(chǎn)實(shí)戰(zhàn)及驗(yàn)證的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-10-10
解決Springboot項(xiàng)目打包后的頁(yè)面丟失問(wèn)題(thymeleaf報(bào)錯(cuò))
這篇文章主要介紹了解決Springboot項(xiàng)目打包后的頁(yè)面丟失問(wèn)題(thymeleaf報(bào)錯(cuò)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
詳解SpringBoot定制@ResponseBody注解返回的Json格式
這篇文章主要介紹了詳解SpringBoot定制@ResponseBody注解返回的Json格式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Java GUI圖形界面開(kāi)發(fā)實(shí)現(xiàn)小型計(jì)算器流程詳解
本文章向大家介紹Java GUI圖形界面開(kāi)發(fā)實(shí)現(xiàn)小型計(jì)算器,主要包括布局管理器使用實(shí)例、應(yīng)用技巧、基本知識(shí)點(diǎn)總結(jié)和需要注意事項(xiàng),具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08
MyBatis代理Dao方式的增刪改查的實(shí)現(xiàn)小結(jié)
本文主要介紹了MyBatis代理Dao方式的增刪改查的實(shí)現(xiàn)小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-11-11
SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn)
微服務(wù)架構(gòu),不可避免的存在單個(gè)微服務(wù)有多個(gè)實(shí)例,這篇文章主要介紹了SpringCloud客戶端的負(fù)載均衡Ribbon的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-06-06
Spring?boot?運(yùn)用策略模式實(shí)現(xiàn)避免多次使用if的操作代碼
這篇文章主要介紹了Spring?boot?運(yùn)用策略模式實(shí)現(xiàn),避免多次使用if,使用策略模式后,新加一種支付策略時(shí),只需要在策略枚舉中添加新加的策略信息,外加一個(gè)策略類即可,而不再需要添加新的if判斷,需要的朋友可以參考下2022-08-08

