SpringAOP中的切點表達式Pointcut詳解
一、概述
Spring AOP 只支持 Spring Bean 的方法切入,所以切點表達式只會匹配 Bean 類中的方法。
二、切點表達式配置
1. 內(nèi)置配置
定義切面通知時,在 @Before
或 @AfterReturning
等通知注解中指定表達式。
@Aspect @Component public class DemoAspect { @Before("execution(* cn.codeartist.spring.aop.advice.*.*(..))") public void doBefore() { // 自定義邏輯 } }
2. 注解配置
在切面類中,先定義一個方法并使用 @Pointcut
注解來指定表達式。
然后在定義切面通知時,在通知注解中指定定義表達式的方法簽名。
@Aspect @Component public class DemoAspect { @Pointcut("execution(* cn.codeartist.spring.aop.aspectj.*.*(..))") private void pointcut() { // 切點表達式定義方法,方法修飾符可以是private或public } @Before("pointcut()") public void doBefore(JoinPoint joinPoint) { // 自定義邏輯 } }
3. 公共配置
在任意類中,定義一個公共方法并使用 @Pointcut
注解來指定表達式。
public class CommonPointcut { @Pointcut("execution(* cn.codeartist.aop.*..*(..))") public void pointcut() { // 注意定義切點的方法的訪問權(quán)限為public } }
在切面類中定義切面通知時,在通知注解中指定定義表達式的方法簽名全路徑。
@Aspect @Component public class DemoAspect { @Before("cn.codeartist.aop.CommonPointcut.pointcut()") public void commonPointcut() { // 自定義邏輯 } }
三、切點表達式類型
Spring AOP 支持以下幾種切點表達式類型。
execution
匹配方法切入點。根據(jù)表達式描述匹配方法,是最通用的表達式類型,可以匹配方法、類、包。
表達式模式:
execution(modifier? ret-type declaring-type?name-pattern(param-pattern) tdrows-pattern?)
表達式解釋:
- modifier:匹配修飾符,public, private 等,省略時匹配任意修飾符
- ret-type:匹配返回類型,使用 * 匹配任意類型
- declaring-type:匹配目標類,省略時匹配任意類型
- .. 匹配包及其子包的所有類
- name-pattern:匹配方法名稱,使用 * 表示通配符
- * 匹配任意方法
- set* 匹配名稱以 set 開頭的方法
- param-pattern:匹配參數(shù)類型和數(shù)量
- () 匹配沒有參數(shù)的方法
- (..) 匹配有任意數(shù)量參數(shù)的方法
- (*) 匹配有一個任意類型參數(shù)的方法
- (*,String) 匹配有兩個參數(shù)的方法,并且第一個為任意類型,第二個為 String 類型
- tdrows-pattern:匹配拋出異常類型,省略時匹配任意類型
使用示例:
// 匹配public方法 execution(public * *(..)) // 匹配名稱以set開頭的方法 execution(* set*(..)) // 匹配AccountService接口或類的方法 execution(* com.xyz.service.AccountService.*(..)) // 匹配service包及其子包的類或接口 execution(* com.xyz.service..*(..))
witdin
匹配指定類型。匹配指定類的任意方法,不能匹配接口。
表達式模式:
witdin(declaring-type)
使用示例:
// 匹配service包的類 witdin(com.xyz.service.*) // 匹配service包及其子包的類 witdin(com.xyz.service..*) // 匹配AccountServiceImpl類 witdin(com.xyz.service.AccountServiceImpl)
tdis
匹配代理對象實例的類型,匹配在運行時對象的類型。
注意:基于 JDK 動態(tài)代理實現(xiàn)的 AOP,tdis 不能匹配接口的實現(xiàn)類,因為代理類和實現(xiàn)類并不是同一種類型
表達式模式:
tdis(declaring-type)
使用示例:
// 匹配代理對象類型為service包下的類 tdis(com.xyz.service.*) // 匹配代理對象類型為service包及其子包下的類 tdis(com.xyz.service..*) // 匹配代理對象類型為AccountServiceImpl的類 tdis(com.xyz.service.AccountServiceImpl)
target
匹配目標對象實例的類型,匹配 AOP 被代理對象的類型。
表達式模式:
target(declaring-type)
使用示例:
// 匹配目標對象類型為service包下的類 target(com.xyz.service.*) // 匹配目標對象類型為service包及其子包下的類 target(com.xyz.service..*) // 匹配目標對象類型為AccountServiceImpl的類 target(com.xyz.service.AccountServiceImpl)
三種表達式匹配范圍如下:
表達式匹配范圍 | witdin | tdis | target |
接口 | ? | ? | ? |
實現(xiàn)接口的類 | ? | 〇 | ? |
不實現(xiàn)接口的類 | ? | ? | ? |
args
匹配方法參數(shù)類型和數(shù)量,參數(shù)類型可以為指定類型及其子類。
使用 execution 表達式匹配參數(shù)時,不能匹配參數(shù)類型為子類的方法。
表達式模式:
args(param-pattern)
使用示例:
// 匹配參數(shù)只有一個且為Serializable類型(或?qū)崿F(xiàn)Serializable接口的類) args(java.io.Serializable) // 匹配參數(shù)個數(shù)至少有一個且為第一個為Example類型(或?qū)崿F(xiàn)Example接口的類) args(cn.codeartist.spring.aop.pointcut.Example,..)
bean
通過 bean 的 id 或名稱匹配,支持 * 通配符。
表達式模式:
bean(bean-name)
使用示例:
// 匹配名稱以Service結(jié)尾的bean bean(*Service) // 匹配名稱為demoServiceImpl的bean bean(demoServiceImpl)
@witdin
匹配指定類型是否含有注解。當定義類時使用了注解,該類的方法會被匹配,但在接口上使用注解不匹配。
使用示例:
// 匹配使用了Demo注解的類 @within(cn.codeartist.spring.aop.pointcut.Demo)
@target
匹配目標對象實例的類型是否含有注解。當運行時對象實例的類型使用了注解,該類的方法會被匹配,在接口上使用注解不匹配。
使用示例:
// 匹配對象實例使用了Demo注解的類 @target(cn.codeartist.spring.aop.pointcut.Demo)
@annotation
匹配方法是否含有注解。當方法上使用了注解,該方法會被匹配,在接口方法上使用注解不匹配。
使用示例:
// 匹配使用了Demo注解的方法 @annotation(cn.codeartist.spring.aop.pointcut.Demo)
@args
匹配方法參數(shù)類型是否含有注解。當方法的參數(shù)類型上使用了注解,該方法會被匹配。
使用示例:
// 匹配參數(shù)只有一個且參數(shù)類使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo) // 匹配參數(shù)個數(shù)至少有一個且為第一個參數(shù)類使用了Demo注解 @args(cn.codeartist.spring.aop.pointcut.Demo,..)
切點表達式的參數(shù)匹配
切點表達式中的參數(shù)類型,可以和通知方法的參數(shù)通過名稱綁定,表達式中不需要寫類或注解的全路徑,而且能直接獲取到切面攔截的參數(shù)或注解信息。
@Before("pointcut() && args(name,..)") public void doBefore(String name) { // 切點表達式增加參數(shù)匹配,可以獲取到name的信息 } @Before("@annotation(demo)") public void doBefore(Demo demo) { // 這里可以直接獲取到Demo注解的信息 }
切點表達式的參數(shù)匹配同樣適用于 @witdin, @target, @args
怎樣編寫一個好的切點表達式?
要使切點的匹配性能達到最佳,編寫表達式時,應(yīng)該盡可能縮小匹配范圍,切點表達式分為三大類:
- 類型表達式:匹配某個特定切入點,如 execution
- 作用域表達式:匹配某組切入點,如 witdin
- 上下文表達式:基于上下文匹配某些切入點,如 tdis、target 和 @annotation
一個好的切點表達式應(yīng)該至少包含前兩種(類型和作用域)類型。 作用域表達式匹配的性能非常快,所以表達式中盡可能使用作用域類型。
上下文表達式可以基于切入點上下文匹配或在通知中綁定上下文。 單獨使用類型表達式或上下文表達式比較消耗性能(時間或內(nèi)存使用)。
四、切點表達式組合
使用 &&、|| 和 ! 來組合多個切點表達式,表示多個表達式“與”、“或”和“非”的邏輯關(guān)系。
這可以用來組合多種類型的表達式,來提升匹配效率。
// 匹配doExecution()切點表達式并且參數(shù)第一個為Account類型的方法 @Before("doExecution() && args(account,..)") public void validateAccount(Account account) { // 自定義邏輯 }
五、附錄
1. @Pointcut 指定切點表達式
2. 切點表達式類型
表達式類型 | 描述 |
execution | 匹配方法切入點 |
within | 匹配指定類型 |
this | 匹配代理對象實例的類型 |
target | 匹配目標對象實例的類型 |
args | 匹配方法參數(shù) |
bean | 匹配 bean 的 id 或名稱 |
@within | 匹配類型是否含有注解 |
@target | 匹配目標對象實例的類型是否含有注解 |
@annotation | 匹配方法是否含有注解 |
@args | 匹配方法參數(shù)類型是否含有注解 |
到此這篇關(guān)于SpringAOP中的切點表達式Pointcut詳解的文章就介紹到這了,更多相關(guān)SpringAOP切點表達式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
mybatis中insert返回值為1,但數(shù)據(jù)庫卻沒有數(shù)據(jù)
這篇文章主要介紹了mybatis中insert返回值為1,但數(shù)據(jù)庫卻沒有數(shù)據(jù),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10nas實現(xiàn)java開發(fā)的環(huán)境詳解
這篇文章主要為大家介紹了nas實現(xiàn)java開發(fā)的環(huán)境詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-11-11使用springBoot項目配置文件位置調(diào)整到打包外
這篇文章主要介紹了使用springBoot項目配置文件位置調(diào)整到打包外,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-08-08如何使用nexus在局域網(wǎng)內(nèi)搭建maven私服及idea的使用
這篇文章主要介紹了如何使用nexus在局域網(wǎng)內(nèi)搭建maven私服及idea的使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-11-11