SpringAOP中@annotation與execution的深度示例對(duì)比分析
在 Spring AOP 中,@annotation 和 execution 是兩種常用的切點(diǎn)表達(dá)式(Pointcut Expression),用于定義哪些方法需要被切面(Aspect)攔截。它們的設(shè)計(jì)目的、匹配規(guī)則和適用場(chǎng)景有顯著區(qū)別,以下從核心機(jī)制、語(yǔ)法、應(yīng)用場(chǎng)景和示例進(jìn)行對(duì)比分析:
?? ?一、核心概念與機(jī)制?
1. ?**@annotation表達(dá)式**?
- ?作用?:匹配帶有特定注解的方法。
- ?原理?:基于方法上的注解標(biāo)記進(jìn)行攔截,與方法的簽名(類名、方法名等)無(wú)關(guān)。
- ?適用場(chǎng)景?:
- 需要為特定功能?(如日志、權(quán)限校驗(yàn))標(biāo)記方法時(shí)。
- 需通過(guò)注解傳遞元數(shù)據(jù)(例如
@Permission(role="admin"))。
- ?優(yōu)點(diǎn)?:靈活性高,與業(yè)務(wù)邏輯解耦,適合自定義橫切關(guān)注點(diǎn)。
- ?缺點(diǎn)?:需顯式在方法上添加注解,無(wú)法批量匹配無(wú)注解的方法。
2. ?**execution表達(dá)式**?
- ?作用?:通過(guò)方法簽名?(返回值、包名、類名、方法名、參數(shù)類型)匹配方法。
- ?原理?:基于方法的結(jié)構(gòu)特征攔截,無(wú)需方法添加額外注解。
- ?適用場(chǎng)景?:
- 批量攔截特定包/類下的所有方法?(如
com.example.service.*.*(..))。 - 按命名規(guī)范匹配方法(如所有
update*開(kāi)頭的方法)。
- 批量攔截特定包/類下的所有方法?(如
- ?優(yōu)點(diǎn)?:無(wú)需修改代碼,適合通用功能(如接口耗時(shí)統(tǒng)計(jì))。
- ?缺點(diǎn)?:表達(dá)式復(fù)雜,對(duì)無(wú)規(guī)則的方法難以精確匹配。
?? ?二、語(yǔ)法詳解?
1. ?**@annotation語(yǔ)法**?
@Before("@annotation(com.example.Loggable)")
public void logBefore(JoinPoint joinPoint) {
// 通知邏輯
}- ?參數(shù)?:注解的全限定類名(如
com.example.Loggable)。 - ?擴(kuò)展?:可與自定義注解結(jié)合,實(shí)現(xiàn)動(dòng)態(tài)控制(例如
@Loggable(level="DEBUG"))。
2. ?**execution語(yǔ)法**?
@Around("execution(* com.example.service.*.*(..))")
public Object monitor(ProceedingJoinPoint pjp) throws Throwable {
// 環(huán)繞通知邏輯
}- ?結(jié)構(gòu)?:
execution(修飾符? 返回值 包.類.?方法名(參數(shù)) 異常?)*:通配任意元素(如返回值、單層包名)。..:通配多層包或任意參數(shù)(如com..*.ServiceImpl匹配com下所有子包的ServiceImpl類)。
- ?示例?:
- 匹配
UserService的所有方法:execution(* com.service.UserService.*(..)) - 匹配所有
save開(kāi)頭的方法:execution(* save*(..))
- 匹配
?? ?三、典型場(chǎng)景對(duì)比?
| ?維度? | ?**@annotation**? | ?**execution**? |
|---|---|---|
| ?匹配依據(jù)? | 方法上的注解標(biāo)記 | 方法簽名(包、類、方法名、參數(shù)等) |
| ?代碼侵入性? | 需在方法上添加注解 | 無(wú)侵入,直接匹配方法結(jié)構(gòu) |
| ?靈活性? | 高(可通過(guò)注解參數(shù)定制邏輯) | 中(依賴方法命名和包結(jié)構(gòu)) |
| ?適用案例? | - 權(quán)限校驗(yàn)(@RequireAuth)- 日志分級(jí)( @LogLevel("DEBUG")) | - 接口耗時(shí)統(tǒng)計(jì) - 全局事務(wù)管理 - 包級(jí)別異常處理 |
| ?復(fù)雜匹配能力? | 弱(僅依賴注解是否存在) | 強(qiáng)(支持通配符、邏輯運(yùn)算符組合) |
?? ?四、代碼示例?
1. ?**@annotation實(shí)現(xiàn)自定義日志**?
// 自定義注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {}
// 切面類
@Aspect
@Component
public class LogAspect {
@Before("@annotation(com.example.Loggable)")
public void logMethodCall(JoinPoint jp) {
System.out.println("Log: " + jp.getSignature().getName());
}
}
// 業(yè)務(wù)方法使用
@Service
public class UserService {
@Loggable
public void createUser() { ... }
}2. ?**execution實(shí)現(xiàn)方法耗時(shí)統(tǒng)計(jì)**?
@Aspect
@Component
public class TimeAspect {
@Around("execution(* com.example.service.*.*(..))")
public Object recordTime(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
Object result = pjp.proceed();
long duration = System.currentTimeMillis() - start;
System.out.println(pjp.getSignature() + " executed in " + duration + "ms");
return result;
}
}? ?五、如何選擇???
- ?優(yōu)先
@annotation?:
當(dāng)需要精細(xì)控制且邏輯與業(yè)務(wù)無(wú)關(guān)時(shí)(如權(quán)限、審計(jì)日志),通過(guò)注解實(shí)現(xiàn)解耦。 - ?優(yōu)先
execution?:
需批量攔截?(如全局性能監(jiān)控)或無(wú)法修改源碼時(shí),通過(guò)方法簽名覆蓋。 - ?混合使用?:
復(fù)雜場(chǎng)景可組合表達(dá)式,例如:
@Before("@annotation(com.example.Auth) && execution(* com.service.*.*(..))")?? ?總結(jié)?
- ?**
@annotation?:注解驅(qū)動(dòng),精準(zhǔn)標(biāo)記方法,適合高定制化橫切邏輯**。 - ?**
execution?:結(jié)構(gòu)驅(qū)動(dòng),無(wú)侵入匹配,適合通用功能增強(qiáng)**。
兩者本質(zhì)是互補(bǔ)工具,實(shí)際開(kāi)發(fā)中需根據(jù)侵入性容忍度、匹配精度和維護(hù)成本綜合選擇。
到此這篇關(guān)于SpringAOP中@annotation與execution的深度對(duì)比的文章就介紹到這了,更多相關(guān)springaop @annotation與execution內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java利用for循環(huán)打印菱形的實(shí)例教程
這篇文章主要給大家介紹了關(guān)于Java利用for循環(huán)打印菱形的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
MyBatis樹(shù)形結(jié)構(gòu)查詢的實(shí)現(xiàn)示例
本文介紹了一種使用MyBatis進(jìn)行樹(shù)形結(jié)構(gòu)查詢的方法,通過(guò)構(gòu)造臨時(shí)表和內(nèi)連接,實(shí)現(xiàn)了不同層級(jí)數(shù)據(jù)的一次性查詢及映射,感興趣的可以了解一下2025-11-11
在SSM中配置了事務(wù)控制但沒(méi)生效的問(wèn)題
這篇文章主要介紹了在SSM中配置了事務(wù)控制但沒(méi)生效的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
SpringBoot AOP控制Redis自動(dòng)緩存和更新的示例
今天小編就為大家分享一篇關(guān)于SpringBoot AOP控制Redis自動(dòng)緩存和更新的示例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-01-01
Java生成Echarts表圖的2種實(shí)現(xiàn)方案
這篇文章主要給大家介紹了關(guān)于Java生成Echarts表圖的2種實(shí)現(xiàn)方案,ECharts是一款功能非常強(qiáng)大的JavaScript圖表庫(kù),文中通過(guò)代碼實(shí)例介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09
Java?實(shí)現(xiàn)判定順序表中是否包含某個(gè)元素(思路詳解)
這篇文章主要介紹了Java?實(shí)現(xiàn)判定順序表中是否包含某個(gè)元素,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-06-06
Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)上文件下載
這篇文章主要為大家詳細(xì)介紹了Java使用組件編寫窗口實(shí)現(xiàn)網(wǎng)上文件下載的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

