亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Spring如何使用AOP實現(xiàn)聲明式事務管理

 更新時間:2025年06月17日 10:09:29   作者:冰糖心書房  
Spring?使用?AOP?實現(xiàn)聲明式事務管理是其最強大的功能之一,這篇文章小編將詳細拆解這個過程,從高層概念到底層原理,感興趣的小伙伴可以參考一下

一、 核心思想:代理模式 + AOP

想象一下,你是一位非常重要的業(yè)務專家(你的 Service 層代碼),你的工作是處理核心業(yè)務邏輯(比如轉賬、更新用戶信息)。但每次處理業(yè)務前,你都需要做一些準備工作(開啟事務),結束后還要做一些收尾工作(提交或回滾事務)。這些準備和收尾工作繁瑣、重復,而且和你的核心業(yè)務關系不大。

聲明式事務管理的目標就是:讓你這位專家只專注于核心業(yè)務,把所有繁瑣的事務管理工作交給一個“管家”來處理。

這個“管家”就是 Spring AOP 創(chuàng)建的代理對象 (Proxy)。

AOP (Aspect-Oriented Programming, 面向切面編程) 在這里扮演的角色就是:

  • 定義“切面” (Aspect):將事務管理(開啟、提交、回滾)這個“橫切關注點”從業(yè)務代碼中抽離出來,形成一個獨立的模塊。
  • 定義“切點” (Pointcut):精確地定義這個“管家”應該在哪些方法執(zhí)行前后介入。在 Spring 中,這通常是通過 @Transactional 注解來指定的。
  • 創(chuàng)建“代理” (Proxy):Spring 不會直接返回你的原始業(yè)務對象,而是會創(chuàng)建一個該對象的代理。所有對業(yè)務對象的調用都會先經(jīng)過這個代理。

二、 詳細工作流程(一步步拆解)

讓我們跟蹤一個對 @Transactional 方法的調用,看看 Spring 內(nèi)部到底發(fā)生了什么。

場景:一個 UserController 調用一個 UserService 的 updateUser() 方法,該方法被 @Transactional 注解。

// 業(yè)務接口
public interface UserService {
    void updateUser(User user);
}

// 業(yè)務實現(xiàn)類
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional // <--- 關鍵注解
    public void updateUser(User user) {
        // 核心業(yè)務邏輯
        userRepository.update(user);
        // 假設這里如果出錯了,需要回滾
        if (user.getName() == null) {
            throw new IllegalArgumentException("Username cannot be null");
        }
    }
}

// 調用方
@RestController
public class UserController {
    @Autowired
    private UserService userService; // <--- 注意:這里注入的其實是代理對象

    @PostMapping("/user/update")
    public void updateUser(@RequestBody User user) {
        userService.updateUser(user);
    }
}

階段一:應用啟動時 - 創(chuàng)建代理

1.Bean 掃描:Spring 容器在啟動時,會掃描所有的 Bean。

2.識別 @Transactional:當 Spring 掃描到 UserServiceImpl 時,它會發(fā)現(xiàn)這個類或其方法上存在 @Transactional 注解。

3.創(chuàng)建代理對象:Spring 認識到這個 Bean 需要被事務“增強”(Advised)。它不會直接創(chuàng)建 UserServiceImpl 的實例并放入容器,而是會通過 AOP 框架為它創(chuàng)建一個代理對象。

  • 如果 UserServiceImpl 實現(xiàn)了接口(如本例中的 UserService),Spring 默認會使用 JDK 動態(tài)代理來創(chuàng)建一個實現(xiàn)了 UserService 接口的代理類。
  • 如果 UserServiceImpl 沒有實現(xiàn)任何接口,Spring 會使用 CGLIB 來創(chuàng)建一個 UserServiceImpl 的子類作為代理。

4.注入代理:當 UserController 通過 @Autowired 請求注入 UserService 時,Spring 容器會將上一步創(chuàng)建的那個代理對象注入給它,而不是原始的 UserServiceImpl 對象。UserController 對此毫不知情,它以為自己拿到的就是普通的 UserService。

階段二:方法調用時 - 事務攔截

1.調用入口:UserController 調用 userService.updateUser(user)。

2.命中代理:這個調用首先命中的是代理對象的 updateUser 方法,而不是原始對象的。

3.事務攔截器 (TransactionInterceptor) 生效:代理對象的這個方法中包含了 AOP 的“通知”(Advice)。對于事務來說,這個通知的具體實現(xiàn)就是 TransactionInterceptor。這個攔截器就像一個警衛(wèi),攔住了這次調用。

4.開啟事務:

  • TransactionInterceptor 首先會解析 updateUser 方法上 @Transactional 注解的屬性(如傳播行為 propagation、隔離級別 isolation、是否只讀 readOnly 等)。
  • 它向事務管理器 (PlatformTransactionManager) 請求一個事務。
  • 事務管理器(例如 DataSourceTransactionManager)會從數(shù)據(jù)庫連接池中獲取一個連接 (Connection),然后執(zhí)行 connection.setAutoCommit(false),這標志著事務的正式開始。

5.調用原始方法:事務成功開啟后,TransactionInterceptor 會通過反射調用原始 UserServiceImpl 對象的 updateUser 方法。

6.執(zhí)行業(yè)務邏輯:此時,才真正開始執(zhí)行你編寫的核心業(yè)務代碼,比如 userRepository.update(user)。所有這些數(shù)據(jù)庫操作都將在上一步獲取的那個被 Spring 管理的 Connection 上執(zhí)行。

階段三:方法執(zhí)行后 - 提交或回滾

當原始的 updateUser 方法執(zhí)行完畢后,控制權返回到 TransactionInterceptor。

1.正常執(zhí)行完畢 (沒有拋出異常):

  • 攔截器捕獲到方法正常返回。
  • 它會通知事務管理器提交 (commit) 事務。
  • 事務管理器調用 connection.commit(),將本次事務中的所有數(shù)據(jù)庫操作永久保存。

2.拋出異常:

  • updateUser 方法內(nèi)部拋出了一個異常(默認是 RuntimeException 或 Error)。
  • 攔截器在其 try-catch 塊中捕獲到這個異常。
  • 它會通知事務管理器回滾 (rollback) 事務。
  • 事務管理器調用 connection.rollback(),撤銷本次事務中的所有數(shù)據(jù)庫操作。
  • 最后,攔截器會將捕獲到的異常繼續(xù)向上拋出,以便上層調用者(如 UserController 或全局異常處理器)能夠感知到。

階段四:收尾

無論事務是提交還是回滾,事務管理器最終都會將數(shù)據(jù)庫連接釋放回連接池。

三、 核心組件總結

@Transactional:元數(shù)據(jù),告訴 AOP 在哪里以及如何應用事務。它本身不包含任何邏輯。

AOP 代理 (Proxy):由 Spring 動態(tài)創(chuàng)建的“管家”對象,是事務邏輯的實際入口。它包裝了原始的業(yè)務對象。

事務攔截器 (TransactionInterceptor):AOP 通知(Advice)的具體實現(xiàn),是代理對象中的核心邏輯。它負責在目標方法調用前后開啟、提交或回滾事務。

事務管理器 (PlatformTransactionManager):一個統(tǒng)一的事務管理接口。Spring 通過它來適配不同的數(shù)據(jù)源技術(如 JDBC, JPA/Hibernate, JTA)。它負責執(zhí)行真正的事務操作(begin, commit, rollback)。

四、 為什么 @Transactional 在某些情況下會失效?

理解了以上原理,就很容易明白為什么 @Transactional 會在以下情況失效:

1.方法不是 public 的:CGLIB 代理是通過繼承來實現(xiàn)的,而 private 或 protected 方法無法被子類重寫(override),所以 AOP 無法攔截。JDK 動態(tài)代理基于接口,更不存在非 public 方法。

2.同一個類中的方法調用(this 調用):

@Service
public class UserServiceImpl implements UserService {
    public void entryMethod() {
        this.updateUser(user); // <--- 失效!
    }

    @Transactional
    public void updateUser(User user) {
        // ...
    }
}

當外部調用 entryMethod() 時,進入的是 UserServiceImpl 的原始對象(如果 entryMethod 沒有被代理)。然后 this.updateUser() 是一個對象內(nèi)部的直接調用,它繞過了代理對象,直接調用了原始對象的 updateUser 方法,因此事務攔截器根本沒有機會介入。

3.異常被 catch 掉了:

@Transactional
public void updateUser(User user) {
    try {
        // ... 拋出 RuntimeException 的代碼
    } catch (Exception e) {
        // 異常被吞了,沒有繼續(xù)拋出
    }
}

事務攔截器是通過捕獲異常來決定是否回滾的。如果異常被你的 try-catch 塊“消化”了,攔截器就認為方法是正常執(zhí)行完畢的,于是它會提交事務,而不是回滾。
通過這個機制,Spring 完美地將業(yè)務邏輯和非功能性的事務管理代碼解耦,讓開發(fā)者能更專注于業(yè)務價值的實現(xiàn),代碼也變得更加清晰和易于維護。

到此這篇關于Spring如何使用AOP實現(xiàn)聲明式事務管理的文章就介紹到這了,更多相關Spring AOP聲明式事務管理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Executor攔截器高級教程QueryInterceptor的規(guī)范

    Executor攔截器高級教程QueryInterceptor的規(guī)范

    今天小編就為大家分享一篇關于Executor攔截器高級教程QueryInterceptor的規(guī)范,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Spring?Cloud?使用?Resilience4j?實現(xiàn)服務熔斷的方法

    Spring?Cloud?使用?Resilience4j?實現(xiàn)服務熔斷的方法

    服務熔斷是為了保護我們的服務,比如當某個服務出現(xiàn)問題的時候,控制打向它的流量,讓它有時間去恢復,或者限制一段時間只能有固定數(shù)量的請求打向這個服務,這篇文章主要介紹了Spring?Cloud?使用?Resilience4j?實現(xiàn)服務熔斷,需要的朋友可以參考下
    2022-12-12
  • Java編程實現(xiàn)的模擬行星運動示例

    Java編程實現(xiàn)的模擬行星運動示例

    這篇文章主要介紹了Java編程實現(xiàn)的模擬行星運動,涉及java基于swing組建繪制動態(tài)效果及數(shù)值運算相關操作技巧,并總結分析了java面向對象的相關特性,需要的朋友可以參考下
    2018-04-04
  • Java二維碼登錄流程實現(xiàn)代碼(包含短地址生成,含部分代碼)

    Java二維碼登錄流程實現(xiàn)代碼(包含短地址生成,含部分代碼)

    近年來,二維碼的使用越來越風生水起,本篇文章主要介紹了Java二維碼登錄流程實現(xiàn)代碼,其中包含短地址生成,有興趣的可以了解一下。
    2016-12-12
  • win10設置java環(huán)境變量的方法

    win10設置java環(huán)境變量的方法

    下面小編就為大家?guī)硪黄獁in10設置java環(huán)境變量的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • 詳細分析Java內(nèi)部類——局部內(nèi)部類

    詳細分析Java內(nèi)部類——局部內(nèi)部類

    這篇文章主要介紹了Java局部內(nèi)部類的相關資料,幫助大家更好的理解和學習Java 內(nèi)部類的知識,感興趣的朋友可以了解下
    2020-08-08
  • Java?JDBC使用入門講解

    Java?JDBC使用入門講解

    JDBC是指Java數(shù)據(jù)庫連接,是一種標準Java應用編程接口(?JAVA?API),用來連接?Java?編程語言和廣泛的數(shù)據(jù)庫。從根本上來說,JDBC?是一種規(guī)范,它提供了一套完整的接口,允許便攜式訪問到底層數(shù)據(jù)庫,本篇文章我們來了解MySQL連接JDBC的流程方法
    2022-12-12
  • spring-boot中spring-boot-maven-plugin報紅錯誤及解決

    spring-boot中spring-boot-maven-plugin報紅錯誤及解決

    這篇文章主要介紹了spring-boot中spring-boot-maven-plugin報紅錯誤及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • java使用apache.poi導出word文件的示例代碼

    java使用apache.poi導出word文件的示例代碼

    這篇文章主要介紹了java使用apache.poi導出word文件,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • maven引入mysql-connector-java包失敗的解決方案

    maven引入mysql-connector-java包失敗的解決方案

    這篇文章主要介紹了maven引入mysql-connector-java包失敗的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02

最新評論