【JavaEE進階】Spring AOP入門

歡迎關注個人主頁:逸狼


創造不易,可以點點贊嗎

如有錯誤,歡迎指出~


AOP是Spring框架的第??核?(第??核?是 IoC)

什么是AOP?

? AspectOrientedProgramming(?向切?編程) 什么是?向切?編程呢?

切?就是指某?類特定問題,所以AOP也可以理解為?向特定?法編程.

什么是?向特定?法編程呢??如"登錄校驗",就是?類特定問題.登錄校驗攔截器,就是對"登錄校驗"這類問題的統?處理.所以,攔截器也是AOP的?種應?.AOP是?種思想,攔截器是AOP 思想的?種實現.Spring框架實現了這種思想,提供了攔截器技術的相關接?.

同樣的,統?數據返回格式和統?異常處理,也是AOP思想的?種實現. 簡單來說: AOP是?種思想,是對某?類事情的集中處理.

什么是SpringAOP?

AOP是?種思想,它的實現?法有很多,有SpringAOP,也有AspectJ、CGLIB等. SpringAOP是其中的?種實現?式. 學會了統?功能之后,是不是就學會了SpringAOP呢,當然不是. 攔截器作?的維度是URL(?次請求和響應),@ControllerAdvice 應?場景主要是全局異常處理 (配合?定義異常效果更佳),數據綁定,數據預處理.AOP作?的維度更加細致(可以根據包、類、?法 名、參數等進?攔截),能夠實現更加復雜的業務邏輯.

舉個例?: 我們現在有?個項?,項?中開發了很多的業務功能

比如想要記錄每個方法的耗時?,記錄開始時間,結束時間,再計算耗時,如果是常規寫法,每個方法都要重復書寫這些代碼,AOP就是將這些重復代碼提取出來,

AOP可以在不改變原有的代碼的前提下, 增強原來方法的功能(?侵?性:解耦)?

    //通過id查詢圖書@RequestMapping("/queryBookById")public BookInfo queryBookById(Integer bookId){long start = System.currentTimeMillis();log.info("獲取圖書信息, bookId: "+ bookId);//參數校驗,不能為null,不能<=0...省略BookInfo bookInfo = bookService.queryBookById(bookId);long end = System.currentTimeMillis();log.info("queryBookById 耗時: " + (end - start) + "ms");return bookInfo;}

?SpringAOP快速??

學習什么是AOP后,我們先通過下?的程序體驗下AOP的開發,并掌握Spring中AOP的開發步驟.

需求:統計圖書系統各個接??法的執?時間.

引?AOP依賴

在pom.xml?件中添加配置

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

統計執?時間

package com.example.demo.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 TimeRecordAspect {//作用域,執行路徑@Around("execution(* com.example.demo.controller.*.*(..))")public Object timeRecord(ProceedingJoinPoint pjt){//1.記錄開始時間//2.執行目標方法時間//3.記錄結束時間//4.返回結果long start = System.currentTimeMillis();//執行目標方法Object o = null;try {o = pjt.proceed();} catch (Throwable e) {e.printStackTrace();}long end = System.currentTimeMillis();log.info(pjt.getSignature() + "耗時: "+ (end - start)+ "ms");return o;}
}
  • 1. @Aspect:標識這是?個切?類
  • 2. @Around:環繞通知,在?標?法的前后都會被執?.后?的表達式表?對哪些?法進?增強.
  • 3. ProceedingJoinPoint.proceed()讓原始?法執?

我們通過AOP??程序完成了業務接?執?耗時的統計. 通過上?的程序,我們也可以感受到AOP?向切?編程的?些優勢:

  1. 代碼?侵?:不修改原始的業務?法,就可以對原始的業務?法進?了功能的增強或者是功能的改變
  2. 減少了重復代碼
  3. 提?開發效率
  4. 維護?便

SpringAOP核?概念

切點(Pointcut)

切點(Pointcut),也稱之為"切?點" Pointcut的作?就是提供?組規則(使?AspectJpointcutexpressionlanguage來描述),告訴程序對 哪些?法來進?功能增強.

表達式execution(* com.example.demo.controller.*.*(..)) 就是切點表達式

連接點(JoinPoint)

滿?切點表達式規則的?法,就是連接點.也就是可以被AOP控制的具體?法 以??程序舉例,所有com.example.demo.controller 路徑下的?法,都是連接點.

切點和連接點的關系 :?

連接點是滿?切點表達式的元素.

切點可以看做是保存了眾多連接點的?個集合.

通知(Advice)

通知就是具體要做的?作,指哪些重復的邏輯,也就是共性功能(最終體現為?個?法) ?如上述程序中記錄業務?法的耗時時間,就是通知.

切?(Aspect)

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

切?所在的類,我們?般稱為切?類(被@Aspect注解標識的類

通知類型

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

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

示例代碼

package com.example.demo.aspect;import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Slf4j
@Component
@Aspect
public class AspectDemo {//前置通知@Before("execution(* com.example.demo.controller.*.*(..))")public void doBefore() {log.info("執? Before ?法");}//后置通知@After("execution(* com.example.demo.controller.*.*(..))")public void doAfter() {log.info("執? After ?法");}//返回后通知@AfterReturning("execution(* com.example.demo.controller.*.*(..))")public void doAfterReturning() {log.info("執? AfterReturning ?法");}//拋出異常后通知@AfterThrowing("execution(* com.example.demo.controller.*.*(..))")public void doAfterThrowing() {log.info("執? doAfterThrowing ?法");}//添加環繞通知@Around("execution(* com.example.demo.controller.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {log.info("Around ?法開始執?");Object result = joinPoint.proceed();log.info("Around ?法結束執?");return result;}
}

?程序正常運?的情況下,@AfterThrowing 標識的通知?法不會執?

從上圖也可以看出來,@Around 標識的通知?法包含兩部分,?個"前置邏輯",?個"后置邏輯".其 中"前置邏輯"會先于 @Before 標識的通知?法執?,"后置邏輯"會晚于 @After 標識的通知?法執??

如果發生異常


?

程序發?異常的情況下:

@AfterReturning 標識的通知?法不會執?, @AfterThrowing 標識的通知?法執?了

@Around 環繞通知中原始?法調?時有異常,通知中的環繞后的代碼邏輯也不會在執?了(因為 原始?法調?出異常了)

@PointCut

上?代碼存在?個問題,就是存在?量重復的切點表達式execution(* com.example.demo.controller.*.*(..)) ,?Spring提供了 @PointCut 注解,把公共的切點 表達式提取出來,需要?到時引?該切?點表達式即可.

@Slf4j
@Aspect
@Component
public class AspectDemo {//定義切點(公共的切點表達式) @Pointcut("execution(* com.example.demo.controller.*.*(..))")private void pt(){}//前置通知 @Before("pt()")public void doBefore() {//...代碼省略 }//后置通知 @After("pt()")public void doAfter() {//...代碼省略 }

當切點定義使?private修飾時,僅能在當前切?類中使?,當其他切?類也要使?當前切點定義時,就需 要把private改為public.引??式為:全限定類名.?法名()?

public class TimeRecordAspect {//    @Around("execution(* com.example.demo.controller.*.*(..))")@Around("com.example.demo.aspect.AspectDemo.pt()")public Object timeRecord(ProceedingJoinPoint pjt){
...}

切?優先級@Order

當我們在?個項?中,定義了多個切?類時,并且這些切?類的多個切?點都匹配到了同?個?標?法. 當?標?法運?的時候,這些切?類中的通知?法都會執?,那么這?個通知?法的執?順序是什么樣 的呢?

存在多個切?類時,默認按照切?類的類名字?排序: ? @Before 通知:字?排名靠前的先執? ? @After 通知:字?排名靠前的后執?

但這種?式不?便管理,我們的類名更多還是具備?定含義的. Spring給我們提供了?個新的注解,來控制這些切?通知的執?順序:@Order 使??式如下:

@Slf4j
@Component
@Aspect
@Order(3)
public class demo1 {
...
}...
@Order(2)
public class demo2 {
...}...
@Order(1)
public class demo3 {
...}

@Order 控制切?的優先級,先執?優先級較?的切?,再執?優先級較低的切?,最終執??標?法.數字越小,優先級越高

切點表達式

上?的代碼中,我們?直在使?切點表達式來描述切點.下?我們來介紹?下切點表達式的語法. 切點表達式常?有兩種表達?式

execution

@annotation

execution表達式

execution()是最常?的切點表達式,?來匹配?法,語法為:

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

其中:訪問 修飾符 和 異常 可以省略

?

切點表達式?例

TestController下的 public修飾,返回類型為String?法名為t1,?參?法

execution(public String com.example.demo.controller.TestController.t1())

省略訪問修飾符

execution(String com.example.demo.controller.TestController.t1())

匹配所有返回類型

execution(* com.example.demo.controller.TestController.t1())

匹配TestController下的所有?參?法

execution(* com.example.demo.controller.TestController.*())

匹配TestController下的所有?法

execution(* com.example.demo.controller.TestController.*(..))

匹配controller包下所有的類的所有?法

execution(* com.example.demo.controller.*.*(..))

匹配所有包下?的TestController

execution(* com..TestController.*(..))

匹配com.example.demo包下,?孫包下的所有類的所有?法

execution(* com.example.demo..*(..))

@annotation

execution表達式更適?有規則的,如果我們要匹配多個?規則的?法呢,?如:TestController中的t1() 和UserController中的u1()這兩個?法. 這個時候我們使?execution這種切點表達式來描述就不是很?便了. 我們可以借助?定義注解的?式以及另?種切點表達式 @annotation 來描述這?類的切點

實現步驟:

1. 編寫?定義注解

2. 使? @annotation 表達式來描述切點

3. 在連接點的?法上添加?定義注解

?定義注解

@TimeRecord 創建?個注解類(和創建Class?件?樣的流程,選擇Annotation就可以了)

package com.example.demo.aspect;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)//運行時
@Target({ElementType.METHOD})//表示作用在方法上public @interface TimeRecord {
}

@Target 標識了 Annotation 所修飾的對象范圍,即該注解可以?在什么地?.

@Retention 指Annotation被保留的時間?短,標明注解的?命周期

切?類

使? @annotation 切點表達式定義切點,只對@TimeRecord?效

@Aspect
@Component
@Slf4j
public class TimeRecordAspect {@Around("@annotation(com.example.demo.aspect.TimeRecord)")public Object timeRecord(ProceedingJoinPoint pjt){//1.記錄開始時間//2.執行目標方法時間//3.記錄結束時間//4.返回結果long start = System.currentTimeMillis();log.info("timeRecord.Around ?法開始執?");//執行目標方法Object o = null;try {o = pjt.proceed();} catch (Throwable e) {e.printStackTrace();}long end = System.currentTimeMillis();log.info(pjt.getSignature() + "耗時: "+ (end - start)+ "ms");log.info("timeRecord.Around ?法結束執?");return o;}
}

在TestController中的t1()和UserController中的u1()這兩個?法上添加?定義注解@TimeRecord ,其他?法不添加

@RequestMapping("/test")
@RestController
@Slf4j
public class TestController {@TimeRecord@RequestMapping("/t1")public String t1(){log.info("執行t1");return "t1";}@RequestMapping("/t2")public int t2(){log.info("執行t2");  return "t2";}
@RequestMapping("/user")
@RestController
@Slf4j
public class UserController {@TimeRecord@RequestMapping("/u1")public String u1(){log.info("執行u1");return "u1";}@RequestMapping("/u2")public String u2(){log.info("執行u2");return "u2";}
}

如果要讓所有帶有@RequestMapping注解的方法都實現記錄時間,只需要將上面的切點表達式換成以下

    @Around("@annotation(org.springframework.web.bind.annotation.RequestMapping)")

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

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

相關文章

算法思想之雙指針(一)

歡迎拜訪&#xff1a;霧里看山-CSDN博客 本篇主題&#xff1a;算法思想之雙指針(一) 發布時間&#xff1a;2025.4.4 隸屬專欄&#xff1a;算法 目錄 雙指針算法介紹對撞指針&#xff1a;快慢指針&#xff1a; 例題移動零題目鏈接題目描述算法思路代碼實現 復寫零題目鏈接題目描…

【11408學習記錄】英語寫作黃金模板+語法全解:用FTC數據泄漏案掌握書信結構與長難句拆解(附思維導圖)

2025.04.04 英語寫作書信寫作第一段私人信件公務信函 語法總結——簡單句簡單句的核心&#xff1a;謂語動詞的變化詞性的拓展限定詞 形容詞與副詞介詞短語 成分的擴展同位語插入語 非謂語動詞 每日一句詞匯 第一步&#xff1a;辨別第二步&#xff1a;斷開第三步&#xff1a;簡化…

手機顯示5GA圖標的條件

最近有星友問在什么情況下才能顯示5G-A&#xff1f;雖然這個我也不知道&#xff0c;但是我有幾個運營商的5G終端白皮書&#xff0c;從上面就可以找到答案。 如上是幾個運營商顯示5G-A的條件&#xff0c;基本上考慮的都是3CC的情況&#xff0c;聯通還有考慮200M CA 2CC的場景&am…

網絡:華為數通HCIA學習:IP路由基礎

華為HCIA學習 IP路由基礎路由協議或路由種類以及對應路由的優先級按工作區域分類&#xff1a;按工作機制及算法分類&#xff1a;路由的優先級路由器選擇最優路由的順序是什么? 前言自治系統LAN和廣播域路由選路IP路由表路由度量建立路由表最長匹配原則路由器轉發數據包總結 IP…

Docker 鏡像相關的基本操作

一、Docker 鏡像基本操作 1. 查找鏡像 命令&#xff1a; docker search <鏡像名稱> 示例&#xff1a;查找 CentOS 鏡像&#xff1a; docker search centos 命令解釋&#xff1a; 默認從 Docker Hub 官方倉庫上搜索鏡像。搜索結果包含多個列&#xff1a; NAME&…

Linux文件特殊權限管理及進程和線程

acl 權限優先級 擁有者 > 特殊指定用戶 > 權限多的組 >權限少的組 > 其他 mask閾值 mask是能夠賦予指定用戶權限的最大閥值 當設定完畢文件的acl列表之后用chmod縮小了文件擁有組的權力 mask會發生變化 恢復&#xff1a; setfacl -m m: 權限 :rwx 文件/…

NVIDIA AgentIQ 詳細介紹

NVIDIA AgentIQ 詳細介紹 1. 引言 NVIDIA AgentIQ 是一個靈活的庫&#xff0c;旨在將企業代理&#xff08;無論使用何種框架&#xff09;與各種數據源和工具無縫集成。通過將代理、工具和代理工作流視為簡單的函數調用&#xff0c;AgentIQ 實現了真正的可組合性&#xff1a;一…

算法設計與分析5(動態規劃)

動態規劃的基本思想 將一個問題劃分為多個不獨立的子問題&#xff0c;這些子問題在求解過程中可能會有些數據進行了重復計算。我們可以把計算過的數據保存起來&#xff0c;當下次遇到同樣的數據計算時&#xff0c;就可以查表直接得到答案&#xff0c;而不是再次計算 動態規劃…

怎么理解量子比特模型,遷移到量子計算機開始編程

怎么理解量子比特模型&#xff0c;遷移到量子計算機開始編程 視頻鏈接&#xff1a; 好的現在是2025年的3月最后一天,3月31號,今天我們討論的話題是量子編程,也就是在量子計算機上,使用特定的語言進行軟件開發。當然我們要討論的,不是,量子編程的某一門語言的技術細節,而是考慮…

使用Expo框架開發APP——詳細教程

在移動應用開發日益普及的今天&#xff0c;跨平臺開發工具越來越受到開發者青睞。Expo 是基于 React Native 的一整套工具和服務&#xff0c;它能夠大幅降低原生開發的門檻&#xff0c;讓開發者只需關注業務邏輯和界面實現&#xff0c;而不用糾結于復雜的原生配置。本文將從零開…

windows技術基礎知識

NT架構 NT 就是new techonology 的英文單詞縮寫&#xff0c;是微軟1993年推出操作系統的重大升級&#xff0c;如內存管理&#xff0c;安全機制&#xff0c;多任務&#xff0c;多線程支持。在此之前操作系統都是基于MS-DOS上面的圖形化界面&#xff0c;只有有限的內存管理和多任…

迪杰斯特拉+二分+優先隊列+拓撲+堆優化(奶牛航線Cowroute、架設電話線dd、路障Roadblocks、奶牛交通Traffic)

原文地址 https://fmcraft.top/index.php/Programming/2025040402.html 主要算法 迪杰斯特拉Dijkstra 題目列表 P1&#xff1a;奶牛航線Cowroute 題目描述 題目描述 Bessie已經厭倦了農場冬天的寒冷氣候&#xff0c;她決定坐飛機去更溫暖的地方去度假。不幸的是&#xf…

#Liunx內存管理# 在32bit Linux內核中,用戶空間和內核空間的比例通常是3:1,可以修改成2:2嗎?

在32位Linux內核中&#xff0c;用戶空間和內核空間的3:1默認比例可以修改為2:2&#xff0c;但需要權衡實際需求和潛在影響。以下是具體分析&#xff1a; 一、修改可行性 1.技術實現 通過內核啟動參數調整虛擬地址空間劃分&#xff0c;例如在GRUB配置中添加mem2G參數&#xff0c…

JAVA:使用 Curator 進行 ZooKeeper 操作的技術指南

1、簡述 Apache Curator 是一個基于 ZooKeeper 的 Java 客戶端庫&#xff0c;它極大地簡化了使用 ZooKeeper 的開發工作。Curator 提供了高層次的 API&#xff0c;封裝了很多復雜的 ZooKeeper 操作&#xff0c;例如連接管理、分布式鎖、Leader 選舉等。 在分布式系統中&#…

Julia語言的測試覆蓋率

Julia語言的測試覆蓋率探討 引言 在現代軟件開發中&#xff0c;測試是確保軟件質量的重要環節。隨著軟件的復雜度不斷增加&#xff0c;測試覆蓋率作為衡量測試質量的一個重要指標&#xff0c;受到了越來越多開發者的關注。Julia語言作為一種高性能的動態編程語言&#xff0c;…

【萬字總結】前端全方位性能優化指南(八)——Webpack 6調優、模塊聯邦升級、Tree Shaking突破

構建工具深度優化——從機械配置到智能工程革命 當Webpack配置項突破2000行、Node進程內存耗盡告警時,傳統構建優化已觸及工具鏈的物理極限:Babel轉譯耗時占比超60%、跨項目模塊復用催生冗余構建、Tree Shaking誤刪關鍵代碼引發線上事故……構建流程正從「工程問題」演變為「…

使用MCP服務器實現AI任務完成通知:讓Cursor更智能

0. 簡介 在使用AI工具進行長時間任務時&#xff0c;常常需要等待結果。MCP&#xff08;Model Context Protocol&#xff09;服務器"mcp_server_notify"提供了一個優雅的解決方案&#xff0c;讓AI在完成任務后通過系統通知提醒你。本文將介紹如何在Cursor中配置和使用…

Java面試黃金寶典33

1. 什么是存取控制、 觸發器、 存儲過程 、 游標 存取控制 定義&#xff1a;存取控制是數據庫管理系統&#xff08;DBMS&#xff09;為保障數據安全性與完整性&#xff0c;對不同用戶訪問數據庫對象&#xff08;如表、視圖等&#xff09;的權限加以管理的機制。它借助定義用戶…

DataX實戰教程

需求&#xff1a; 用datax同步mysql&#xff1a; 192.168.236.134中test1庫的user表到192.168.236.136中test1庫的user表 步驟&#xff1a; 下載安裝包 https://github.com/alibaba/DataX/blob/master/userGuid.md 進入引導頁 https://github.com/alibaba/DataX/blob/ma…

C#/.NET/.NET Core技術前沿周刊 | 第 32 期(2025年3.24-3.31)

前言 C#/.NET/.NET Core技術前沿周刊&#xff0c;你的每周技術指南針&#xff01;記錄、追蹤C#/.NET/.NET Core領域、生態的每周最新、最實用、最有價值的技術文章、社區動態、優質項目和學習資源等。讓你時刻站在技術前沿&#xff0c;助力技術成長與視野拓寬。 歡迎投稿、推薦…