javascript
学习Spring Boot:(二十二)使用 AOP
前言
AOP,意為:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。基于AOP實現的功能不會破壞原來程序邏輯,因此它可以很好的對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。
正文
Spring Boot 中使用
默認為 false。
切點表達式
列出常用的幾個表達式:
execution() 滿足execution中描述的方法簽名。 execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)throws-pattern?)
* modifier-pattern:表示方法的修飾符;
* ret-type-pattern:表示方法的返回值
* declaring-type-pattern:表示方法所在的類的路徑
* name-pattern:表示方法名
* param-pattern:表示方法的參數
* throws-pattern:表示方法拋出的異常
* 其中后面跟著?的是可選項。
this()是用來限定方法所屬的類,為接口則限定所有的實現類,為類的話,限定這單個類。
@annotation表示具有某個標注的方法。
args 表示方法的參數屬于一個特定的類,@args 表示參數有特定的標注注解。
within 包或者類型滿足within中描述的包或者類型的類的所有非私有方法,@within 類型擁有@target描述中給出的annotation,其中@target和@within的區別在于@within要求的annotation的級別為CLASS,而@target為RUNTIME
. target 業務實例對象(非代理實例)的類型滿足target 中的描述的類型,@target 類型擁有@target描述中給出的annotation
bean() 表示所有匹配的 bean,例如 ,bean(“*Service”),匹配所有 Service 結尾的類。可以使用 !bean() 表示不匹配。
注意事項:
* 在各個pattern中,可以使用”*”來表示匹配所有。
* 在param-pattern中,可以指定具體的參數類型,多個參數間用,隔開,各個也可以用 * 來表示匹配任意類型的參數,如(String)表示匹配一個String參數的方法;(*,String)表示匹配有兩個參數的方法,第一個參數可以是任意類型,而第二個參數是String類型。
* 可以用(..)表示零個或多個任意的方法參數。
* 使用&&符號表示與關系,使用||表示或關系、使用!表示非關系。在XML文件中使用and、or和not這三個符號。
AspectJ提供了五種定義通知的標注:
- @Before:前置通知,在調用目標方法之前執行通知定義的任務
- @After:后置通知,在目標方法執行結束后,無論執行結果如何都執行通知定義的任務
- @AfterReturning:后置通知,在目標方法執行結束后,如果執行成功,則執行通知定義的任務
- @AfterThrowing:異常通知,如果目標方法執行過程中拋出異常,則執行通知定義的任務
- @Around:環繞通知,在目標方法執行前和執行后,都需要執行通知定義的任務
通過標注定義通知只需要兩個步驟:
創建環繞通知
環繞通知相比其它四種通知有其特殊之處。環繞通知本質上是將前置通知、后置通知和異常通知整合成一個單獨的通知。
用@Around標注的方法,該方法必須有一個ProceedingJoinPoint類型的參數,
在方法體中,需要通過這個參數,以joinPoint.proceed();的形式調用目標方法。注意在環繞通知中必須進行該調用,否則目標方法本身的執行就會被跳過。
計算方法的執行時間:
@Around("logPointCut()") //切點public Object around(ProceedingJoinPoint point) throws Throwable {long beginTime = System.currentTimeMillis();//執行方法Object result = point.proceed();//執行時長(毫秒)long time = System.currentTimeMillis() - beginTime;return result;}處理通知中參數
獲取參數的方式則需要使用關鍵詞是args。
@Pointcut("bean(sysUserServiceImpl) && args(userEntity,..)")public void userPointCut(SysUserEntity userEntity) {}@Before("userPointCut(userEntity)")public void validateUser(SysUserEntity userEntity) {// to handler args}這里有個非常嚴格的一點就是,args(userEntity,..),表示目標方法,可能有多個參數,但是包括 userEntity,這里 userEntity 必須參數名相同,不同就編織了。
args()中參數的名稱必須跟切點方法的簽名中public void validateUser(SysUserEntity userEntity)的參數名稱相同。如果使用切點函數定義,其中的參數名稱也必須與通知方法簽名中的參數完全相同
AfterReturning增強處理
@AfterReturning(pointcut = "logPointCut()", returning = "rtv")public void logAfter(Object rtv) {System.out.println(Objects.toString(rtv));}使用 @AfterReturning 注解時,指定了一個returning屬性,假設該屬性值為rvt,這表明允許在Advice方法(logAfter()方法)中定義名為rvt的形參,程序可通過rvt形參來訪問目標方法的返回值。
注意:
雖然AfterReturning增強處理可以訪問到方法的返回值,但它不可以改變目標方法的返回值。
AOP切面的優先級
有時候,我們對一個方法會有多個切面的問題,這個時候還會涉及到切面的執行順序的問題。
我們可以定義每個切面的優先級, Spring 中提供注解 @Order(i) ,當 i 的值越小,優先級越高。
參考文章
- Spring AOP中定義切點(PointCut)和通知(Advice)
- Spring Boot中使用AOP統一處理Web請求日志
總結
以上是生活随笔為你收集整理的学习Spring Boot:(二十二)使用 AOP的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python3精要(23)-递归与函数列
- 下一篇: SpringCloud 超详细个人笔记