【JavaEE】Spring AOP的注解實現

目錄

  • 一、AOP 與 Spring AOP
  • 二、Spring AOP簡單實現
  • 三、詳解Spring AOP
    • 3.1 Spring AOP 核心概念
      • 3.1.1 切點(Pointcut)
      • 3.1.2 連接點(Join Point)
      • 3.1.3 通知(Advice)
      • 3.1.4 切面(Aspect)
    • 3.2 通知類型
    • 3.3 公共切點引用@PointCut
    • 3.4 切點優先級@Order
    • 3.5 切點表達式
      • 3.5.1 execution
      • 3.5.2 @annotation

一、AOP 與 Spring AOP

AOP:Aspect Oriented Programming(?向方?編程)。是一種對某一類事情集中處理的思想。

Spring AOP:就是對AOP思想的一種實現。

二、Spring AOP簡單實現

我們簡單實現一個統計每個接口的用時。

引入依賴:

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

寫AOP實現:

  • 類使用注解@Aspect修飾
  • 方法參數為ProceedingJoinPoint 類,代表要實現的方法(只能在Around通知下寫)
  • 方法使用注解@Around,參數是對應的路徑的切點
  • ProceedingJoinPoint 的參數執行proceed方法。
package com.example.library.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;@Aspect
@Component
@Slf4j
public class TimeAspect {@Around("execution(* com.example.library.controller.*.*(..) )")public Object recordTime(ProceedingJoinPoint  proceedingJoinPoint) throws Throwable {//開始時間long start = System.currentTimeMillis();//執行方法Object result = proceedingJoinPoint.proceed();//結束時間long end = System.currentTimeMillis();log.info("執行時間:"+ (end-start) + "ms");return result;}
}

三、詳解Spring AOP

3.1 Spring AOP 核心概念

Spring AOP 核心概念:切點,連接點,通知,切面。

我們以上面的代碼來介紹。

3.1.1 切點(Pointcut)

切點:就是告訴程序哪些方法需要使用到接下來的功能。
上面的@Around注解的參數就是切點表達式。

3.1.2 連接點(Join Point)

連接點:滿?切點表達式規則的?法,就是連接點。也就是可以AOP控制的?法。

就像上面的代碼的連接點就是:com.example.library.controller路徑下的所有方法。

切點和連接點的關系:

  • 連接點是滿?切點表達式的元素。
  • 切點可以看做是保存了眾多連接點的?個集合。

3.1.3 通知(Advice)

通知:這個Spring AOP方法要實現的功能就是通知。

就像上面的實現一個統計每個接口的用時的需求,就是通知。

3.1.4 切面(Aspect)

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

通過切?就能夠描述當前AOP程序需要針對于哪些?法,在什么時候執?什么樣的操作。
切?既包含了通知邏輯的定義,也包括了連接點的定義。

3.2 通知類型

Spring中AOP的通知類型有以下?種:

  • @Around:環繞通知,此注解標注的通知?法在?標?法前,后都被執?。
  • @Before:前置通知,此注解標注的通知?法在?標?法前被執?。
  • @After:后置通知,此注解標注的通知?法在?標?法后被執?,?論是否有異常都會執?。
  • @AfterReturning:返回后通知,此注解標注的通知?法在?標?法后被執?,有異常不會執?。
  • @AfterThrowing:異常后通知,此注解標注的通知?法發?異常后執?。

效果:

package com.example.demoaop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Aspect
public class TestAspect {//前置通知@Before("execution(* com.example.demoaop.*.*(..) )")public void testBefore() {log.info("Before 方法執行前");}//后置通知@After("execution(* com.example.demoaop.*.*(..) )")public void testAfter() {log.info("After 方法執行后");}//返回后通知@AfterReturning("execution(* com.example.demoaop.*.*(..) )")public void testAfterReturning() {log.info("AfterReturning 返回后通知");}//拋出異常后通知@AfterThrowing("execution(* com.example.demoaop.*.*(..) )")public void testAfterThrowing() {log.info("AfterThrowing 拋出異常后通知");}//環繞通知@Around("execution(* com.example.demoaop.*.*(..) )")public void testAround(ProceedingJoinPoint pjp) throws Throwable {log.info("Around 方法執行前");Object proceed = pjp.proceed();log.info("Around 方法執行后");}
}

3.3 公共切點引用@PointCut

當我們的切點表達式是一樣的時候,像上面我們還是在每一個通知類型的注解中,都使用了相同的表達式。
我們就可以使用方法注解@PointCut將切點表達式提取出來,然后后面使用只需要寫方法名即可。
在其他切點類中也可以調用,需要將@PointCut注解所在類的路徑寫出來。

package com.example.demoaop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Aspect
public class TestAspect {@Pointcut("execution(* com.example.demoaop.*.*(..) )")public void pc(){}//前置通知@Before("pc()")public void testBefore() {log.info("TestAspect Before 方法執行前");}//后置通知@After("pc()")public void testAfter() {log.info("TestAspect After 方法執行后");}
}
package com.example.demoaop;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Component
@Slf4j
@Aspect
public class TestAspect2 {//前置通知@Before("com.example.demoaop.TestAspect.pc()")public void testBefore() {log.info("TestAspect2 Before 方法執行前");}//后置通知@After("pc()")public void testAfter() {log.info("TestAspect2 After 方法執行后");}}

結果:
可以看見生效了,而且在其他切點類中只有加上了路徑的才生效了。

3.4 切點優先級@Order

我們定義3個一樣的切點類,看他們的輸出順序:

存在多個切?類時,默認按照切?類的類名字?排序:

  • @Before 通知:字?排名靠前的先執?
  • @After 通知:字?排名靠前的后執?
    但這種?式不?便管理,我們的類名更多還是具備?定含義的。
    Spring 給我們提供了?個新的注解,來控制這些切?通知的執?順序:@Order

我們將切點類的優先級換一下:

@Component
@Slf4j
@Aspect
@Order(1)
public class TestAspect3 {//前置通知@Before("com.example.demoaop.TestAspect.pc()")public void testBefore() {log.info("TestAspect3 Before 方法執行前");}//后置通知@After("com.example.demoaop.TestAspect.pc()")public void testAfter() {log.info("TestAspect3 After 方法執行后");}}
@Component
@Slf4j
@Aspect
@Order(2)
public class TestAspect2 {//前置通知@Before("com.example.demoaop.TestAspect.pc()")public void testBefore() {log.info("TestAspect2 Before 方法執行前");}//后置通知@After("com.example.demoaop.TestAspect.pc()")public void testAfter() {log.info("TestAspect2 After 方法執行后");}}
@Component
@Slf4j
@Aspect
@Order(3)
public class TestAspect {@Pointcut("execution(* com.example.demoaop.*.*(..) )")public void pc(){}//前置通知@Before("pc()")public void testBefore() {log.info("TestAspect Before 方法執行前");}//后置通知@After("pc()")public void testAfter() {log.info("TestAspect After 方法執行后");}
}

執行結果:

規律:
@Order 注解標識的切?類,執?順序如下:

  • @Before 通知:數字越?先執?
  • @After 通知:數字越?先執?

像下圖的表示,箭頭代表執行過程:

3.5 切點表達式

切點表達式用來描述切點,常有以下兩種類型的切點表達式:execution 和 @annotation

3.5.1 execution

語法:

execution(<訪問修飾限定符> <返回類型> <包名.類名.方法名(方法參數)> <異常>)

含義:

  • 訪問修飾限定符:表示切點對應的方法的訪問修飾限定符
  • 返回類型:表示切點對應的方法的返回類型
  • 包名.類名.方法名(方法參數):表示切點對應的方法的路徑及參數
  • 異常:表示切點對應的方法拋出的異常
  • 訪問修飾限定符 和 異常 可以省略

切點表達式?持通配符表達:

  1. :* 匹配任意字符,只匹配?個元素(返回類型,包,類名,?法或者?法參數)
    1.1. 包名使? * 表?任意包(?層包使??個 * )
    1.2. 類名使? * 表?任意類
    1.3. 返回值使? * 表?任意返回值類型
    1.4. ?法名使? * 表?任意?法
    1.5. 參數使? * 表??個任意類型的參數
  2. : 兩個點 . . 匹配多個連續的任意符號,可以通配任意層級的包,或任意類型,任意個數的參數
    2.1. 使? . . 配置包名,標識此包以及此包下的所有?包
    2.2. 可以使? . . 配置參數,任意個任意類型的參數

例子:

  • TestController 下的 public修飾,返回類型為String ?法名為t1的?參?法
execution(public String com.example.demo.TestController.t1())
  • 匹配 TestController 下的所有?參?法
execution(* com.example.demo.TestController.*())
  • 匹配controller包下所有的類的所有?法
execution(* com.example.demo.controller.*.*(..))

3.5.2 @annotation

當我們要落實到不同類下個幾個方法,用上面的execution就有點捉襟見肘。
我們就可以使用?定義注解的?式以及另?種切點表達式 @annotation 來描述這?類的切點。

自定義注解:

  • 在自定義類的時候選擇annotation:
  • 然后就跟我們前面使用的注解一樣包含,生命周期@Retention,作用范圍@Target,交給Spring管理。
@Component
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAspect {
}

定義切面類:

  • 使用@Aspect注解修飾,
  • 交給Spring管理
  • 在通知類型的注解中使用:@annotation(自定義注解路徑) 作為參數。
@Slf4j
@Component
@Aspect
public class MyAspectDemo {@Around("@annotation( com.example.demoaop.MyAspect)")public void around(ProceedingJoinPoint pjp) throws Throwable {log.info("annotation 運行前");pjp.proceed();log.info("annotation 運行后");}
}

通過上面的方法,使用了自定義注解修飾的方法,就可以添加切面類的通知。

@RequestMapping("/test")
@RestController
@Slf4j
public class Test {@RequestMapping("/f1")public String f1() {log.info("f1");return "s1";}@MyAspect@RequestMapping("/f2")public Integer f2() {log.info("f2");return 1;}@RequestMapping("/f3")public Boolean f3() {log.info("f3");return false;}
}

訪問f2 f1 f3 的結果:

除了上面講的基于注解的方式實現Spring AOP 還有遠古的通過xml和代理的方式實現。參考Spring AOP其它實現方式

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

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

相關文章

協作開發攻略:Git全面使用指南 — 結語

協作開發攻略&#xff1a;Git全面使用指南 — 結語 Git 是一種分布式版本控制系統&#xff0c;用于跟蹤文件和目錄的變更。它能幫助開發者有效管理代碼版本&#xff0c;支持多人協作開發&#xff0c;方便代碼合并與沖突解決&#xff0c;廣泛應用于軟件開發領域。 文中內容僅限技…

如何用AI主動突出畫面主體!涂鴉新方案助剪輯、工業巡檢、醫療影像等領域,實現自動追蹤+智能放大

隨著智能 IPC 設備&#xff08;如安防攝像頭、寵物陪伴機器人、嬰兒監視器等&#xff09;日益普及&#xff0c;越來越多的生活場景被實時記錄。然而在實際使用中&#xff0c;由于設備安裝位置不當、廣角鏡頭視野過大等原因&#xff0c;經常會出現拍攝主體占比過小的問題&#x…

數據湖DataLake和傳統數據倉庫Datawarehouse的主要區別是什么?優缺點是什么?

數據湖和傳統數據倉庫的主要區別 以下是數據湖和傳統數據倉庫的主要區別&#xff0c;以表格形式展示&#xff1a; 特性數據湖傳統數據倉庫數據類型支持結構化、半結構化及非結構化數據主要處理結構化數據架構設計扁平化架構&#xff0c;所有數據存儲在一個大的“池”中多層架…

當智駕成標配,車企暗戰升級|2025上海車展

文&#xff5c;劉俊宏 編&#xff5c;王一粟 智能化無處不在的2025年上海車展&#xff0c;回歸了賣車的初衷。 光錐智能在展會暴走兩天&#xff0c;最大的感觸是今年的車展少了爭奇斗艷&#xff0c;多了些許務實。 回顧智能汽車時代的三場重要車展。2023年的上海車展充滿了…

如何在Spring Boot中禁用Actuator端點安全性

在 Spring Boot 應用中&#xff0c;Spring Boot Actuator 提供了一系列用于監控和管理應用的端點&#xff08;如 /actuator/health、/actuator/metrics&#xff09;&#xff0c;這些端點默認可能受到 Spring Security 的保護&#xff0c;要求身份驗證或授權。然而&#xff0c;在…

【mongodb】系統保留的數據庫名

目錄 1. admin2. config3. local4. test&#xff08;非嚴格保留&#xff0c;但常作為默認測試數據庫&#xff09;5. 注意事項6. 其他相關說明 1. admin 1.用途&#xff1a;用于存儲數據庫的權限和用戶管理相關數據。2.特點&#xff1a;該數據庫是 MongoDB 的超級用戶數據庫&am…

Redis是單線程的,如何提高多核CPU的利用率?

一句話回答&#xff1a; Redis 是單線程處理客戶端命令&#xff0c;但可以通過 多實例部署、I/O 多路復用、后臺線程 Redis 6 的 I/O Thread 支持&#xff0c;來充分利用多核 CPU。 一、Redis 單線程 ≠ 整個 Redis 都是單線程&#xff01; Redis 主要的 網絡事件 命令執行 …

關于mysql的事務和索引

1. 事務四大特性&#xff08;ACID&#xff09; 原子性&#xff1a;事務的操作要么全部成功&#xff0c;要么全部失敗回滾&#xff0c;不可分割。 一致性&#xff1a;事務執行前后&#xff0c;數據必須滿足業務規則&#xff08;如賬戶總額不變&#xff09;。 隔離性&#xff1…

【Python】保持Selenium穩定爬取的方法(防檢測策略)

selenium 防檢測策略的方法匯總&#xff1a; 合理設置延遲&#xff1a;請求間添加隨機延遲 (2-10秒) 限制爬取頻率&#xff1a;控制每小時/每天的請求量 輪換用戶代理&#xff1a;準備至少10個不同的User-Agent 使用住宅代理&#xff1a;優先選擇高質量的住宅代理IP 處理驗…

SpringSecurity源碼解讀AbstractAuthenticationProcessingFilter

一、介紹 AbstractAuthenticationProcessingFilter 是 Spring Security 框架里的一個抽象過濾器,它在處理基于表單的認證等認證流程時起著關鍵作用。它繼承自 GenericFilterBean,并實現了 javax.servlet.Filter 接口。此過濾器的主要功能是攔截客戶端發送的認證請求,對請求…

什么是DDD?為什么它正在取代傳統架構?

什么是DDD&#xff1f;為什么它正在取代傳統架構&#xff1f; 1. 傳統開發模式的痛點 在經典的MVC架構中&#xff0c;開發流程往往從數據庫表結構設計開始&#xff0c;業務邏輯散落在Service層&#xff0c;隨著需求迭代容易形成「大泥球」代碼&#xff1a; 實體類變成純粹的…

基于外部中中斷機制,實現以下功能: 1.按鍵1,按下和釋放后,點亮LED 2.按鍵2,按下和釋放后,熄滅LED 3.按鍵3,按下和釋放后,使得LED閃爍

題目&#xff1a; 參照外部中斷的原理和代碼示例,再結合之前已經實現的按鍵切換LED狀態的實驗&#xff0c;用外部中斷改進其實現。 請自行參考文檔《中斷》當中&#xff0c;有關按鍵切換LED狀態的內容, 自行連接電路圖&#xff0c;基于外部中斷機制&#xff0c;實現以下功能&am…

在SQL中,FROM子句中的子查詢必須指定別名,即使后續未引用該別名

FROM子句中的子查詢必須指定別名 示例錯誤示例及原因&#xff1a;總結&#xff1a; 在SQL中&#xff0c; FROM子句中的子查詢必須指定別名&#xff0c; 即使后續未引用該別名 示例 查詢館藏圖書最多的作者姓名及館藏數量 SELECT 作者, COUNT(圖書編號) AS 館藏數量 FROM 圖…

問道數碼獸 懷舊劇情回合手游源碼搭建教程(反查重優化版)

本文將對"問道數碼獸"這一經典卡通風格回合制手游的服務端部署與客戶端調整流程進行詳細拆解&#xff0c;適用于具備基礎 Windows 運維和手游源碼調試經驗的開發者參考使用。教程以實戰為導向&#xff0c;基于原始說明內容重構優化&#xff0c;具備較高的內容查重避重…

Shell腳本-for循環應用案例

在Shell腳本編程中&#xff0c;for循環是一種強大的工具&#xff0c;用于處理重復性任務。無論是批量處理文件、遍歷目錄內容還是簡單的計數任務&#xff0c;for循環都能提供簡潔而有效的解決方案。本文將通過幾個實際的應用案例來展示如何使用for循環解決具體的編程問題。 案…

Chrmo手動同步數據

地址欄輸入 chrome://sync-internals分別點擊這2個按鈕即可觸發手動同步

為什么圓形在GeoJSON中被表示為多邊形(Polygon)而不是圓形類型

GeoJSON規范中沒有"圓形"類型 GeoJSON是一種用于表示地理空間數據的標準格式,它的規范中只定義了以下幾種基本幾何類型: Point (點) LineString (線) Polygon (多邊形) MultiPoint (多點) MultiLineString (多線) MultiPolygon (多多邊形) GeometryCollection (幾…

大數據組件學習之--Kafka 安裝搭建

一、前置環境 在搭建kafka之前&#xff0c;請確認自己的hadoop、zookeeper是否搭建完成且可正常運行 二、下載并上傳安裝包&#xff08;鏈接為百度網盤&#xff09; kafka安裝包 tar -zxvf /opt/software/kafka_2.12-2.4.1.tgz -C /opt/module/ 進入解壓后的目錄更改文件名…

PyQt6基礎_pyqtgraph_折線圖with縮放調節

目錄 字符型橫坐標代碼 折線圖代碼 運行 創建新類&#xff0c;繼承pg.PlotWidget&#xff0c;在新類中實現業務內容&#xff0c;重寫pg.PlotWidget中的wheelEvent方法并使用業務數據實現比較理想的縮放狀態。 字符型橫坐標代碼 class StrAxisItem(pg.AxisItem):def __init…

聯邦元學習實現個性化物聯網的框架

隨著數據安全和隱私保護相關法律法規的出臺&#xff0c;需要直接在中央服務器上收集和處理數據的集中式解決方案&#xff0c;對于個性化物聯網而言&#xff0c;訓練各種特定領域場景的人工智能模型已變得不切實際。基于此&#xff0c;中山大學&#xff0c;南洋理工大學&#xf…