Spring AOP---面向切面編程由認識到使用

1. AOP

AOP(Aspect-Oriented Programming), 是一種思想, 面向切面編程。

在前文統一異常處理,統一結果返回就是使用了這一思想(都是在集中處理某一類事情, 但又不影響原有代碼的正常運行),但他們不是AOP,只是應用了這一思想。

共同點就是:不修改目標方法,而達到了對目標方法功能的增強(就像MybatisPlus對Mybatis)?

AOP是一種思想, 實現它的方式有很多: SpringAOP, AspectJ, CGLIB, ....等

Spring 共有兩大核心機制, 一個是 Spring IoC, 一個就是 Spring AOP.

在這句話中,第一個 "Spring" 指的是 Spring Framework,而不是 Spring Boot。

原因是,Spring IoC(控制反轉)和 Spring AOP(面向切面編程)是 Spring Framework 的兩大核心特性。這些特性是 Spring Framework 的基礎,Spring Boot 則是在 Spring Framework 的基礎上進行封裝和簡化配置,使得開發者能更快速地構建應用。

Spring IoC 主要負責對象的管理和依賴注入。

Spring AOP 用于面向切面編程,通過代理機制提供橫切關注點(如日志、事務管理等)。

Spring Boot 作為 Spring Framework 的擴展,簡化了配置和開發流程,但核心機制(如 IoC 和 AOP)依然是基于 Spring Framework 的。所以當提到 "Spring 的核心機制" 時,通常是指 Spring Framework 中的 IoC 和 AOP。?

關于面向切面編程的講解會在應用中體現?

2. Spring AOP 入門

2.1 引入 Spring AOP 依賴

Spring AOP 依賴不能在創建項目時引入, 必須手動引入

        <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>

2.2 Spring AOP 簡單使用

我們使用 Spring AOP 編寫一個程序, 記錄接口的執行時長.

@Slf4j
@Aspect
@Component
public class TimeAspect {//公共切點表達式@Pointcut("@annotation(com.cym.spring_aop.aspect.MyAspect)")private void pt(){}@Around("pt()")public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {//記錄方法執行前的時間long begin = System.currentTimeMillis();//方法執行Object result = pjp.proceed();//記錄方法執行后的時間long end = System.currentTimeMillis();log.info(pjp.getSignature() + ",耗費時間:{}" , end - begin);return result;}
}

如上圖所示, 通過 Spring AOP, 我們只需在外部通過 Spring AOP 就可以獲取到接口的執行時長. 達到了 "獲取執行時長" 這一功能和業務代碼的解耦

如果不使用 Spring AOP, 我們就需要在每個接口的起始位置和結束位置獲取時間戳, 再計算執行時長, 這樣不僅入侵了業務代碼, 還需要手動對每個要實現這個功能的接口都編寫這些代碼(對于懶人是一定不能接受的吧)

3.Spring AOP 詳解

3.1 核心概念

Spring AOP 有以下 4 個核心概念:

  1. 切點
  2. 連接點
  3. 通知
  4. 切面

舉個例子:
假如你要在所有 Controller 方法執行前打印日志,那么:

切點(Pointcut) = "所有 Controller 里的方法"(切點可以看做是保存了眾多連接點的?個集合

連接點(JoinPoint)= "Controller 中某個具體的方法"(滿?切點表達式規則的?法

通知(Advice) = "方法執行前,打印日志"(對他說:開工吧)

切面(Aspect) = "攔截所有 Controller 方法,在執行前打印日志"

切?(Aspect) = 切點(Pointcut) + 通知(Advice)

?

3.1.1?切點


切點(Pointcut)本質上只是一個篩選規則, 它不會影響代碼執行, 也不會真正“攔截”任何東西, 它只是告訴 Spring 要對哪些方法進行攔截, 對哪些方法生效.

3.1.1.1 @Pointcut 定義切點

切點 = @Pointcut 注解(聲明切點) + 切點表達式(定義規則)


切點表達式是切點的一部分, 它決定了切點的“篩選規則”.

切點通過切點表達式定義一套規則, 這個規則表名了對哪些方法生效/攔截哪些方法(是一個集合), 描述哪些方法可能成為連接點

可以選擇直接在@Around中寫表達式:

@Around("execution(* com.cym.spring_aop.controller.*.*(..))")

也可以寫在 pt()中:(可以復用,推薦)

    //公共切點表達式@Pointcut("execution(* com.cym.spring_aop.controller.*.*(..))")private void pt(){}@Around("pt()")

?還可以在其他切面中使用(使用時, 需要寫出這個切點的全限定名):

com.cym.spring_aop.aspect.TimeAspect.pt()
3.1.1.2 切點表達式


常見的切點表達式有以下兩種:

execution: 根據方法的簽名來匹配 (如上圖所示)
@annotation(......): 根據注解匹配


execution 表達式:

語法:

其中,?訪問限定修飾符和異常可以省略.

以execution(* com.cym.spring_aop.controller.*.*(..))為例:

    /*** 1.TestController 下的 public修飾, 返回類型為String ?法名為t1, ?參?法* execution(public String com.example.demo.controller.TestController.t1())* 2.省略訪問修飾符* execution(String com.example.demo.controller.TestController.t1())* 3.匹配所有返回類型* execution(* com.example.demo.controller.TestController.t1())* 4.匹配TestController 下的所有?參?法* execution(* com.example.demo.controller.TestController.*())* 5.匹配TestController 下的所有?法* execution(* com.example.demo.controller.TestController.*(..))* 6.匹配controller包下所有的類的所有?法* execution(* com.example.demo.controller.*.*(..))* 7.匹配所有包下?的TestController* execution(* com..TestController.*(..))* 8.匹配com.example.demo包下, ?孫包下的所有類的所有?法* execution(* com.example.demo..*(..))*/

@annotation 表達式:


通過 execution 定義切點表達式, Spring AOP 攔截的是符合方法簽名規則的方法.

而通過 @annotation 定義切點表達式, Spring AOP 攔截的是標注了特定注解的方法(可以是自定義注解, 也可以是 Spring 提供的注解), 因此更加靈活.

@annotation 中, 需要寫出該注解的完全限定名.

1.第一步定義自定義注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {}

@Target(ElementType.METHOD):標識該注解只能作用于方法

@Retention(RetentionPolicy.RUNTIME):表示注解只存活在運行時,在編譯好的文件中不存在

2.在需要攔截的方法前加上該注解

3.根據該注解定義切點表達式

    @Pointcut("@annotation(com.cym.spring_aop.aspect.MyAspect)")private void pt(){}@Around("pt()")

3.1.2 連接點

包含在切點表達式中的某個具體的方法, 在程序執行過程中實際被執行的那個方法,?就是一個連接點(即目標方法).

幸運兒,在增強中間執行的方法

  • 切點(Pointcut)是一個篩選規則,用來定義哪些方法(連接點)會被 AOP 代理。

  • 連接點(Join Point)是具體的方法,符合切點規則的方法就是連接點。

3.1.3 通知(Advice)


通知(Advice), 就是 AOP 攔截到目標方法(連接點)后, 具體要做的事/具體要執行的邏輯.

簡單來說, 通知就是決定攔截后要做什么事情 .

切點(Pointcut) 只是一個“篩選規則”,它決定哪些方法(連接點)需要被攔截,但它本身不執行任何邏輯.

通知(Advice) 是真正 “干活的人”,它決定攔截后要做什么事情(比如打印日志、權限校驗、事務管理等)

3.1.3.1 通知類型

Spring AOP 提供了 5 種常見的通知,不同的通知類型, 執行的時機不同:

? @Around: 環繞通知, 此注解標注的通知?法在?標?法前, 后都被執?

? @Before: 前置通知, 此注解標注的通知?法在?標?法前被執?

? @After: 后置通知, 此注解標注的通知?法在?標?法后被執?, ?論是否有異常都會執?

? @AfterReturning: 返回后通知, 此注解標注的通知?法在?標?法后被執?,

有異常不會執?

? @AfterThrowing: 異常后通知, 此注解標注的通知?法發?異常后執?

代碼演示:

    /*** 前置通知*/@Before("execution(* com.cym.spring_aop.controller.*.*(..))")public void doBefore() {System.out.println("執行doBefore方法");}/*** 后置通知*/@After("execution(* com.cym.spring_aop.controller.*.*(..))")public void doAfter() {System.out.println("執行doAfter方法");}/***拋出異常后通知*/@AfterThrowing("execution(* com.cym.spring_aop.controller.*.*(..))")public void doAfterThrowing() {System.out.println("執行doAfterThrowing方法");}/*** 返回后通知*/@AfterReturning("execution(* com.cym.spring_aop.controller.*.*(..))")public void doAfterReturning() {System.out.println("執行doAfterReturning方法");}/*** 返回后通知*/@Around("execution(* com.cym.spring_aop.controller.*.*(..))")public Object Around(ProceedingJoinPoint pjp) throws Throwable {System.out.println("執行Around方法前..");Object result = pjp.proceed();System.out.println("執行Around方法后..");return result;}

?程序正常運行的情況下, @AfterThrowing 標識的通知方法不會執行, 只有拋出異常時, 該通知方法才會執行.

正常執行:

發現執行順序:@Around? ?>? @doBefore? >? @doAferReturning? >? @doAfter? >? @Around

接下來我們添加一個異常 執行一下:

發現執行順序:@Around? ?>? @doBefore? >? @doAferThrowing? >? @doAfter?

3.1.4 切面優先級

Spring AOP 允許多個切面作用于同一個目標方法.

當多個切面類, 作用于同一個目標方法(連接點)時, 切面之間是有優先級的:

  • 先執行優先級高的切面中的通知, 后執行優先級低的切面中的通知.

默認的切面優先級是按照名稱來排序的:

不加優先級:

加了優先級?

@Order(1)
@Slf4j
@Aspect
@Component
public class Aspect2 {
...
}
@Order(2)
@Slf4j
@Aspect
@Component
public class Aspect3 {
...
}

注意:?

對于 JDK 代理. Spring AOP 只對 public 修飾的方法生效,即切點匹配的目標方法必須是 public, 切面的通知才會生效.
對于 CGLib 代理, Spring AOP 對非 private 非 final 修飾的方法生效,即切點匹配的目標方法不能是 private 或者 final 的.
SpringBoot 默認使用的是 CGLib 代理.?
綜上, 如果要對我們項目中的某個方法進行 AOP 攔截通知, 那么這個方法不能是 private 或者 final 修飾的.

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

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

相關文章

專題二十四:虛擬專用網絡

一、VPN簡介 VPN&#xff08;Virtual Personal Network&#xff09;即虛擬專用網&#xff0c;泛指通過VPN技術在公用網絡上構建的虛擬專用網絡。VPN用戶在此虛擬網絡中傳輸私網流量&#xff0c;在不改變網絡現狀的情況下實現安全、可靠的連接。其主要功能是在公用網絡上建立專…

Milvus(12):分析器

1 分析器概述 在文本處理中&#xff0c;分析器是將原始文本轉換為結構化可搜索格式的關鍵組件。每個分析器通常由兩個核心部件組成&#xff1a;標記器和過濾器。它們共同將輸入文本轉換為標記&#xff0c;完善這些標記&#xff0c;并為高效索引和檢索做好準備。 在 Milvus 中&a…

Power Query精通指南1:查詢結構設計、數據類型、數據導入與遷移(平面文件、Excel、Web)

文章目錄 零、Power Query簡介0.1 Power Query 主要功能0.2 Power Query 的優勢0.3 Power Query 組件 一、Power Query數據處理基本流程1.1 前期準備1.2 提取1.3 轉換1.3.1 Power Query 編輯器界面1.3.2 默認轉換1.3.3 自定義轉換 1.4 加載1.4.1 自動檢測數據類型1.4.2 重命名查…

WebRTC 服務器之Janus概述和環境搭建

1 概述 Janus 是由 Meetecho 開發的通用 WebRTC 服務器&#xff0c;它為構建 WebRTC 應用程序提供了一個模塊化框架。服務器目標&#xff1a;Janus WebRTC 網關被設計為輕量級、通用的 WebRTC 服務器&#xff0c;除了實現以下方法外&#xff0c;它本身不提供任何功能&#xff1…

19:常見的Halcon數據格式

遍歷文件夾與文件選擇 1&#xff09;遍歷文件夾&#xff1a; list_files( : : Directory, Options : Files) Directory&#xff1a;目錄&#xff08;文件夾路徑&#xff09; Options&#xff1a;選項 files 指定搜索的格式為文件 directories 指定搜索的格式為文件夾 re…

QML圖像提供器 (Image Provider)

QML 中的圖像提供器是一種自定義圖像加載機制&#xff0c;允許你從非文件源&#xff08;如數據庫、網絡或程序生成的內容&#xff09;提供圖像數據。 主要類型 QQuickImageProvider - 基礎圖像提供器 QPixmapImageProvider - 提供 QPixmap 圖像 QImageImageProvider - 提供 …

計算機視覺與深度學習 | 雙目立體匹配算法理論+Opencv實踐+matlab實踐

雙目立體匹配 一、雙目立體匹配算法理論與OpenCV、matlab實踐一、雙目立體匹配理論二、OpenCV實踐三、優化建議四、算法對比與適用場景二、雙目立體匹配算法理論及Matlab實踐指南一、雙目立體匹配理論二、Matlab實踐步驟三、算法對比與優化建議四、完整流程示例五、常見問題與解…

AI國學智慧語錄視頻,條條視頻10W+播放量

家人們&#xff01;圖書類帶貨玩法真的非常多&#xff0c;之前也分享過蠻多&#xff0c;例如情感語錄、育兒教育、爆款圖書金句類、AI歷史人物解說類等等。 本期繼續來分享一個對于普通人來說&#xff0c;上手相當簡單&#xff0c;容易起號&#xff0c;可作為長線深耕的AI帶貨…

echart圖表使用

2、接口編寫 該部分代碼定義了UserController控制器類&#xff0c;用于處理與用戶相關的請求。包含一個用于跳轉頁面的方法和一個返回用戶詳細數據&#xff08;以 JSON 格式呈現&#xff09;的接口。前者負責將用戶導航至指定頁面&#xff0c;后者通過構建ChartVO對象并填充數…

Android短信監控技術實現:合法合規的遠程采集方案

一年經驗的全棧程序員&#xff0c;目前頭發健在&#xff0c;但不知道能撐多久。 該項目已成功部署并穩定運行于企業生產環境&#xff0c;如需個性化定制方案&#xff0c;歡迎聯系作者進行深度合作。 文章目錄 前言 一、頁面設計 1.頁面顯示 2.代碼實現 二、具體代碼實現 1.添加…

前端跨域問題怎么在后端解決

目錄 簡單的解決方法&#xff1a; 添加配置類&#xff1a; 為什么會跨域 1. 什么是源 2. URL結構 3. 同源不同源舉&#x1f330; 同源例子 不同源例子 4. 瀏覽器為什么需要同源策略 5. 常規前端請求跨域 簡單的解決方法&#xff1a; 添加配置類&#xff1a; packag…

【中間件】brpc_基礎_execution_queue

execution_queue 源碼 1 簡介 execution_queue.h 是 Apache BRPC 中實現 高性能異步任務執行隊列 的核心組件&#xff0c;主要用于在用戶態線程&#xff08;bthread&#xff09;中實現任務的 異步提交、有序執行和高效調度。 該模塊通過解耦任務提交與執行過程&#xff0c;提…

java學習之數據結構:一、數組

主要是對數組所有的東西進行總結&#xff0c;整理 適合小白~ 目錄 1.什么是數組 1.1數組定義 1.2數組創建 1&#xff09;靜態創建 2&#xff09;動態創建 1.3數組遍歷 1&#xff09;for和while遍歷 2&#xff09;foreach遍歷 2.數組越界問題及解決 2.1數組越界問題 2…

[Survey]SAM2 for Image and Video Segmentation: A Comprehensive Survey

BaseInfo TitleSAM2 for Image and Video Segmentation: A Comprehensive SurveyAdresshttps://arxiv.org/abs/2503.12781Journal/Time2503Author四川大學&#xff0c;北京大學 1. Introduction 圖像分割專注于識別單個圖像中的目標、邊界或紋理&#xff0c;而視頻分割則將這…

用Maven定位和解決依賴沖突

用Maven定位和解決依賴沖突 一、依賴沖突的常見表現二、定位沖突依賴的4種方法2.1 使用Maven命令分析依賴樹2.2 使用IDE可視化工具2.3 使用Maven Enforcer插件2.4 運行時分析 三、解決依賴沖突的5種方案3.1 排除特定傳遞依賴3.2 統一指定版本&#xff08;推薦&#xff09;3.3 使…

穿越數據森林與網絡迷宮:樹與圖上動態規劃實戰指南

在 C 算法的浩瀚宇宙中&#xff0c;樹與圖就像是神秘的迷宮和茂密的森林&#xff0c;充滿了未知與挑戰。而動態規劃則是我們探索其中的神奇羅盤&#xff0c;幫助我們找到最優路徑。今天&#xff0c;就讓我們一起深入這片神秘領域&#xff0c;揭開樹與圖上動態規劃的神秘面紗&am…

UDP / TCP 協議

目錄 一、前言&#xff1a; 數據封裝與分用&#xff1a; 二、網絡協議分層模型&#xff1a; 三、UDP / TCP 協議 UDP 協議&#xff1a; 1、UDP 協議段格式&#xff1a; 2、UDP 的特點&#xff1a; TCP 協議&#xff1a; 1、TCP 協議段格式&#xff1a; 2、TCP 協議的十…

Python 實現的運籌優化系統數學建模詳解(動態規劃模型)

相關代碼鏈接&#xff1a;https://download.csdn.net/download/heikediguoshinib/90713747?spm1001.2014.3001.5503 一、引言 在計算機科學與數學建模的廣闊領域中&#xff0c;算法如同精密的齒輪&#xff0c;推動著問題的解決與系統的運行。當面對復雜的優化問題時&…

langfuse本地安裝

目錄 安裝命令項目準備用openai測試 安裝命令 本地&#xff08;docker compose&#xff09;&#xff1a;使用 Docker Compose 在你的機器上于 5 分鐘內運行 Langfuse。 # 獲取最新的 Langfuse 倉庫副本 git clone https://github.com/langfuse/langfuse.git cd langfuse# 運行 …

每天學一個 Linux 命令(35):dos2unix

每天學一個 Linux 命令(35):dos2unix 命令簡介 dos2unix 是一個用于將 Windows/DOS 格式的文本文件轉換為 Unix/Linux 格式的實用工具。它主要處理行尾符的轉換(將 CRLF 轉換為 LF),同時也能處理編碼問題和字符集轉換。這個命令在跨平臺文件共享、代碼遷移和系統管理場…