Spring Aop @After (后置通知)的使用場景?

在這里插入圖片描述

核心定義

@After 是 Spring AOP 中的另一種通知(Advice)類型,通常被稱為“后置通知”“最終通知”

它的核心作用是:

無論目標方法是正常執行完成,還是在執行過程中拋出了異常,@After 通知中的代碼 總是 會在目標方法執行之后被執行。

最經典的類比就是 Java 中的 try...catch...finally 語句塊里的 finally 部分。@After 的行為和 finally 塊的行為幾乎一模一樣。


@After 通知的執行流程

為了更好地理解,我們來看兩種情況下的執行順序:

情況一:目標方法成功執行

  1. @Before 通知執行。
  2. 目標方法 (targetMethod()) 執行并正常返回。
  3. @After 通知執行。
  4. (如果定義了)@AfterReturning 通知執行。

情況二:目標方法拋出異常

  1. @Before 通知執行。
  2. 目標方法 (targetMethod()) 執行,中途拋出異常。
  3. @After 通知執行。
  4. (如果定義了)@AfterThrowing 通知執行。
  5. 異常繼續向上層調用棧拋出。

一個非常關鍵的點是:@After 通知本身無法訪問目標方法的返回值(因為它可能根本沒有返回值,比如拋異常時),也無法捕獲或處理從目標方法中拋出的異常。它只是一個保證“最后一定會被執行”的鉤子。


@After 通知能做什么?(主要應用場景)

后置通知非常適合執行那些必須進行的“清理”或“收尾”工作,無論業務邏輯成功與否。

  1. 資源釋放 (Resource Cleanup)

    • 這是 @After 最重要、最常見的用途。類似于 finally 塊。
    • 示例:釋放文件句柄、關閉網絡連接、關閉數據庫連接池中的連接等。確保即使業務代碼出錯,關鍵資源也不會被泄露。
  2. 上下文清理 (Context Cleanup)

    • 如果在 @Before 通知中向 ThreadLocal 存放了數據,那么在 @After 通知中將其 remove() 是一個最佳實踐。這可以防止在線程池環境中發生內存泄漏或數據錯亂。
  3. 最終日志記錄 (Final Auditing)

    • 記錄一個操作的結束。
    • 示例:“方法 updateProduct 執行完畢。” 這個日志不關心成功或失敗,只記錄“結束”這個事實。
  4. 性能監控 (Performance Monitoring)

    • 可以在 @Before 中記錄一個開始時間,然后在 @After 中記錄結束時間,并計算總耗時。
    • 示例
      • @Before: long startTime = System.currentTimeMillis(); (存入 ThreadLocal)
      • @After: long endTime = System.currentTimeMillis(); long duration = endTime - startTime; log.info("方法耗時: {} ms", duration);

@AfterReturning@AfterThrowing 的區別

這是新手很容易混淆的地方,理解它們的區別至關重要:

通知類型執行時機能否訪問返回值?能否訪問異常?主要用途
@After (最終通知)總是在目標方法后執行(無論成功或失敗)不能不能資源清理、最終日志
@AfterReturning (返回通知)僅在目標方法成功執行后執行可以不適用基于返回結果的附加操作
@AfterThrowing (異常通知)僅在目標方法拋出異常后執行不適用可以異常日志記錄、告警通知

簡單來說:

  • 總是執行清理?用 @After
  • 想在成功后根據返回值做點事?用 @AfterReturning
  • 想在失敗后專門處理異常?用 @AfterThrowing

代碼示例

我們擴展之前的例子,增加一個刪除方法(可能會失敗),并為所有方法添加 @After 通知。

1. 業務服務類 (目標對象)

package com.example.service;import org.springframework.stereotype.Service;@Service
public class UserService {// 成功執行的例子public String findUserById(Long id) {System.out.println("--- 核心業務邏輯:正在根據 ID 查詢用戶... ---");return "User" + id;}// 拋出異常的例子public void deleteUser(Long id) {System.out.println("--- 核心業務邏輯:正在嘗試刪除用戶... ---");if (id <= 0) {throw new IllegalArgumentException("用戶ID無效,刪除失敗!");}System.out.println("用戶 " + id + " 已被成功刪除。");}
}

2. 切面類 (Aspect) 中定義 @After 通知

package com.example.aop;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
import java.util.Arrays;@Aspect
@Component
public class LoggingAspect {@Pointcut("execution(public * com.example.service.*.*(..))")public void serviceLayerPointcut() {}// 前置通知@Before("serviceLayerPointcut()")public void logBefore(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();Object[] args = joinPoint.getArgs();System.out.println("==================================================");System.out.printf("[AOP 前置通知]: 方法 [%s] 即將執行... 參數: %s%n", methodName, Arrays.toString(args));}// 后置通知 (最終通知)@After("serviceLayerPointcut()")public void logAfter(JoinPoint joinPoint) {String methodName = joinPoint.getSignature().getName();System.out.printf("[AOP 后置通知]: 方法 [%s] 執行完畢。執行清理工作...%n", methodName);System.out.println("--------------------------------------------------\n");}
}

3. 運行代碼并觀察輸出

調用成功的方法 userService.findUserById(101L):

==================================================
[AOP 前置通知]: 方法 [findUserById] 即將執行... 參數: [101]
--- 核心業務邏輯:正在根據 ID 查詢用戶... ---
[AOP 后置通知]: 方法 [findUserById] 執行完畢。執行清理工作...
--------------------------------------------------

@After 在方法成功后執行了。

調用失敗的方法 userService.deleteUser(0L) (需要用 try-catch 捕獲異常):

try {userService.deleteUser(0L);
} catch (Exception e) {System.err.println("在調用方捕獲到異常: " + e.getMessage());
}

輸出:

==================================================
[AOP 前置通知]: 方法 [deleteUser] 即將執行... 參數: [0]
--- 核心業務邏輯:正在嘗試刪除用戶... ---
[AOP 后置通知]: 方法 [deleteUser] 執行完畢。執行清理工作...
--------------------------------------------------在調用方捕獲到異常: 用戶ID無效,刪除失敗!

即使 deleteUser 拋出了異常,@After 通知 (logAfter 方法) 依然被執行了,完美地展示了其 finally 的特性。

總結

特性描述
執行時機無論成功或失敗,總是在目標方法執行之后執行。
核心用途資源釋放上下文清理、最終日志記錄等收尾工作。
行為類似Java 的 finally 語句塊。
關鍵限制無法訪問目標方法的返回值,也無法捕獲或修改異常。
關鍵參數可以注入 JoinPoint 對象,獲取方法元數據。

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

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

相關文章

UNet改進(4):交叉注意力(Cross Attention)-多模態/多特征交互

在計算機視覺領域&#xff0c;UNet因其優異的性能在圖像分割任務中廣受歡迎。本文將介紹一種改進的UNet架構——UNetWithCrossAttention&#xff0c;它通過引入交叉注意力機制來增強模型的特征融合能力。 1. 交叉注意力機制 交叉注意力(Cross Attention)是一種讓模型能夠動態地…

C#里從CSV文件加載BLOB數據字段到數據庫的處理

大量的數據保存在CSV文件, 當需要把這些數據加載到數據庫,然后使用數據庫來共享出去。 就需要把CSV文件導入數據庫, 怎么樣快速地把CSV文件導入數據庫呢? 這個就需要使用類MySqlBulkLoader,它是mariadb數據庫快速導入的方式。 一般使用SQL語句導入是10秒,那么使用這種方…

【后端】負載均衡

長期不定期更新補充。 定義 負載均衡&#xff08;Load Balancing&#xff09;是指將來自客戶端的請求合理分發到多個服務器或服務節點&#xff0c;以提高系統性能、可用性與可靠性。 分工 前端不做負載均衡&#xff0c;前端只發請求&#xff0c;不知道請求去哪臺服務器。 負…

記錄一次:Java Web 項目 CSS 樣式/圖片丟失問題:一次深度排查與根源分析

記錄一次&#xff1a;Java Web 項目 CSS 樣式/圖片丟失問題&#xff1a;一次深度排查與根源分析 **記錄一次&#xff1a;Java Web 項目 CSS 樣式丟失問題&#xff1a;一次深度排查與根源分析****第一層分析&#xff1a;資源路徑問題****第二層分析&#xff1a;服務端跳轉邏輯**…

torchmd-net開源程序是訓練神經網絡潛力

?一、軟件介紹 文末提供程序和源碼下載 TorchMD-NET 提供最先進的神經網絡電位 &#xff08;NNP&#xff09; 和訓練它們的機制。如果有多個 NNP&#xff0c;它可提供高效、快速的實現&#xff0c;并且它集成在 GPU 加速的分子動力學代碼中&#xff0c;如 ACEMD、OpenMM 和 …

在Docker上安裝Mongo及Redis-NOSQL數據庫

應用環境 Ubuntu 20.04.6 LTS (GNU/Linux 5.15.0-139-generic x86_64) Docker version 28.1.1, build 4eba377 文章目錄 一、部署Mongo1. 拉取容器鏡像2. 生成Run腳本2.1 準備條件2.2 參數解讀2.3 實例腳本 3. 實例操作3.1 Mongo bash控制臺3.2 庫表操作 4. MongoDB Compass (G…

Java 編程之責任鏈模式

一、什么是責任鏈模式&#xff1f; 責任鏈模式&#xff08;Chain of Responsibility Pattern&#xff09; 是一種行為型設計模式&#xff0c;它讓多個對象都有機會處理請求&#xff0c;從而避免請求的發送者和接收者之間的耦合關系。將這些對象連成一條鏈&#xff0c;沿著這條…

1、做中學 | 一年級上期 Golang簡介和安裝環境

一、什么是golang Golang&#xff0c;通常簡稱 Go&#xff0c;是由 Google 公司的 Robert Griesemer、Rob Pike 和 Ken Thompson 于 2007 年創建的一種開源編程語言&#xff0c;并在 2009 年正式對外公布。 已經有了很多編程語言&#xff0c;為什么還要創建一種新的編程語言&…

Linux--迷宮探秘:從路徑解析到存儲哲學

上一篇博客我們說完了文件系統在硬件層面的意義&#xff0c;今天我們來說說文件系統在軟件層是怎么管理的。 Linux--深入EXT2文件系統&#xff1a;數據是如何被組織、存儲與訪問的&#xff1f;-CSDN博客 &#x1f30c; 引言&#xff1a;文件系統的宇宙觀 "在Linux的宇宙中…

淘寶商品數據實時獲取方案|API 接口開發與安全接入

在電商數據獲取領域&#xff0c;除了官方 API&#xff0c;第三方數據 API 接入也是高效獲取淘寶商品數據的重要途徑。第三方數據 API 憑借豐富的功能、靈活的服務&#xff0c;為企業和開發者提供了多樣化的數據解決方案。本文將聚焦第三方數據 API 接入&#xff0c;詳細介紹其優…

什么是防抖和節流?它們有什么區別?

文章目錄 一、防抖&#xff08;Debounce&#xff09;1.1 什么是防抖&#xff1f;1.2 防抖的實現 二、節流&#xff08;Throttle&#xff09;2.1 什么是節流&#xff1f;2.2 節流的實現方式 三、防抖與節流的對比四、總結 在前端開發中&#xff0c;我們經常會遇到一些高頻觸發的…

Springboot集成阿里云OSS上傳

Springboot集成阿里云OSS上傳 API 接口描述 DEMO提供的四個API接口&#xff0c;支持不同方式的文件和 JSON 數據上傳&#xff1a; 1. 普通文件上傳接口 上傳任意類型的文件 2. JSON 字符串上傳接口 上傳 JSON 字符串 3. 單個 JSON 壓縮上傳接口 上傳并壓縮 JSON 字符串…

刪除大表數據注意事項

數據庫是否會因刪除操作卡死&#xff0c;沒有固定的 “安全刪除條數”&#xff0c;而是受數據庫配置、表結構、操作方式、當前負載等多種因素影響。以下是關鍵影響因素及實踐建議&#xff1a; 一、導致數據庫卡死的核心因素 硬件與數據庫配置 CPU / 內存瓶頸&#xff1a;刪除…

Redis 是單線程模型?|得物技術

一、背景 使用過Redis的同學肯定都了解過一個說法&#xff0c;說Redis是單線程模型&#xff0c;那么實際情況是怎樣的呢&#xff1f; 其實&#xff0c;我們常說Redis是單線程模型&#xff0c;是指Redis采用單線程的事件驅動模型&#xff0c;只有并且只會在一個主線程中執行Re…

[特殊字符] AIGC工具深度實戰:GPT與通義靈碼如何徹底重構企業開發流程

&#x1f50d; 第一模塊&#xff1a;理念顛覆——為什么AIGC不是“玩具”而是“效能倍增器”&#xff1f; ▍企業開發的核心痛點圖譜&#xff08;2025版&#xff09; ??研發效能瓶頸??&#xff1a;需求膨脹與交付時限矛盾持續尖銳&#xff0c;傳統敏捷方法論已觸天花板?…

(LeetCode 面試經典 150 題) 169. 多數元素(哈希表 || 二分查找)

題目&#xff1a;169. 多數元素 方法一&#xff1a;二分法&#xff0c;最壞的時間復雜度0(nlogn)&#xff0c;但平均0(n)即可。空間復雜度為0(1)。 C版本&#xff1a; int nnums.size();int l0,rn-1;while(l<r){int mid(lr)/2;int ans0;for(auto x:nums){if(xnums[mid]) a…

(17)java+ selenium->自動化測試-元素定位大法之By css上

1.簡介 CSS定位方式和xpath定位方式基本相同,只是CSS定位表達式有其自己的格式。CSS定位方式擁有比xpath定位速度快,且比CSS穩定的特性。下面詳細介紹CSS定位方式的使用方法。相對CSS來說,具有語法簡單,定位速度快等優點。 2.CSS定位優勢 CSS定位是平常使用過程中非常重要…

【軟考高級系統架構論文】企業集成平臺的技術與應用

論文真題 企業集成平臺是一個支持復雜信息環境下信息系統開發、集成和協同運行的軟件支撐環境。它基于各種企業經營業務的信息特征,在異構分布環境(操作系統、網絡、數據庫)下為應用提供一致的信息訪問和交互手段,對其上運行的應用進行管理,為應用提供服務,并支持企業信息…

i.MX8MP LVDS 顯示子系統全解析:設備樹配置與 DRM 架構詳解

&#x1f525; 推薦&#xff1a;《Yocto項目實戰教程&#xff1a;高效定制嵌入式Linux系統》 京東正版促銷&#xff0c;歡迎支持原創&#xff01; 鏈接&#xff1a;https://item.jd.com/15020438.html i.MX8MP LVDS 顯示子系統全解析&#xff1a;設備樹配置與 DRM 架構詳解 在…

keep-alive實現原理及Vue2/Vue3對比分析

一、keep-alive基本概念 keep-alive是Vue的內置組件&#xff0c;用于緩存組件實例&#xff0c;避免重復渲染。它具有以下特點&#xff1a; 抽象組件&#xff1a;自身不會渲染DOM&#xff0c;也不會出現在父組件鏈中包裹動態組件&#xff1a;緩存不活動的組件實例&#xff0c;…