spring aop的@Before,@Around,@After,@AfterReturn,@AfterThrowing的理解


aop的這幾個注解的使用非常常見,但是他們的執行順序,以及作為我們進入核心代碼前的校驗,是如何在校驗失敗不然他進入核心方法的?博客上確實有不少講解的很詳細,我在結尾也會推薦幾篇。這里就幾個重要的點和不明的點做下說明,前事不忘后事之師!

1.AOP的基本概念

切面(Aspect) :通知(advice)和切入點(pointcut)共同組成了切面(aspect),時間、地點和要發生的“故事”。可以從注解方式來理解,代碼如下。 
@aspect為類上面的注解——切面 
@pointcut(…)——切入點。為此類內一個空方法上面的注解。可以把攔截的地址表達式表示為方法簽名,利於使用起來方便。 
@before@after等——通知。為此類下面的方法上面的注解。 
三者在一塊組成一個切面。

@Aspect public class ExampleAspect { @Pointcut("execution(* com.psjay.example.spring.aop.*.*(..))") public void aPointcut() { } @Before("aPointcut()") public void beforeAdvice() { System.out.println("before advice is executed!"); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12



連接點(Joinpoint) :程序能夠應用通知的一個“時機”,這些“時機”就是連接點,例如方法被調用時、異常被拋出時等等。——可以理解為被aop攔截的類或者方法就是連接點。

通知(Advice) :通知定義了切面是什么以及何時使用。描述了切面要完成的工作和何時需要執行這個工作。——可以理解為被注解有@Before等advice注解的安全校驗的方法,攔截了過來的請求要做什么邏輯的校驗。

切入點(Pointcut) :通知定義了切面要發生的“故事”和時間,那么切入點就定義了“故事”發生的地點,例如某個類或方法的名稱。——可以理解為切面切向哪里?是個類或者某層的包路徑。 
目標對象(Target Object) :即被通知的對象。 
AOP代理(AOP Proxy) 在Spring AOP中有兩種代理方式,JDK動態代理和CGLIB代理。默認情況下,TargetObject實現了接口時,則采用JDK動態代理;反之,采用CGLIB代理。 
織入(Weaving)把切面應用到目標對象來創建新的代理對象的過程,織入一般發生在如下幾個時機: 
  (1)編譯時:當一個類文件被編譯時進行織入,這需要特殊的編譯器才能做到,例如AspectJ的織入編譯器; 
  (2)類加載時:使用特殊的ClassLoader在目標類被加載到程序之前增強類的字節代碼; 
  (3)運行時:切面在運行的某個時刻被織入,SpringAOP就是以這種方式織入切面的,原理是使用了JDK的動態代理。

2 通知(Advice)類型的說明

@Before 前置通知(Before advice) :在某連接點(JoinPoint)——核心代碼(類或者方法)之前執行的通知,但這個通知不能阻止連接點前的執行。為啥不能阻止線程進入核心代碼呢?因為@Before注解的方法入參不能傳ProceedingJoinPoint,而只能傳入JoinPoint。要知道從aop走到核心代碼就是通過調用ProceedingJionPoint的proceed()方法。而JoinPoint沒有這個方法。 
這里牽扯區別這兩個類:Proceedingjoinpoint 繼承了 JoinPoint 。是在JoinPoint的基礎上暴露出 proceed 這個方法。proceed很重要,這個是aop代理鏈執行的方法。暴露出這個方法,就能支持 aop:around 這種切面(而其他的幾種切面只需要用到JoinPoint,這跟切面類型有關), 能決定是否走代理鏈還是走自己攔截的其他邏輯。建議看一下 JdkDynamicAopProxy的invoke方法,了解一下代理鏈的執行原理。這樣你就能明白 proceed方法的重要性。

@After 后通知(After advice) :當某連接點退出的時候執行的通知(不論是正常返回還是異常退出)。

@AfterReturning 返回后通知(After return advice) :在某連接點正常完成后執行的通知,不包括拋出異常的情況。

@Around 環繞通知(Around advice) :包圍一個連接點的通知,類似Web中Servlet規范中的Filter的doFilter方法。可以在方法的調用前后完成自定義的行為,也可以選擇不執行。這時aop的最重要的,最常用的注解。用這個注解的方法入參傳的是ProceedingJionPoint pjp,可以決定當前線程能否進入核心方法中——通過調用pjp.proceed();

@AfterThrowing 拋出異常后通知(After throwing advice) : 在方法拋出異常退出時執行的通知。

3 advice(通知)注解的執行先后順序

這里說下簡單情況——針對一個方法只被一個aspect類攔截時,aspect類內部的 advice 將按照以下的順序進行執行情況如下: 
這里寫圖片描述

這里寫圖片描述 
解釋:執行到核心業務方法或者類時,會先執行AOP。在aop的邏輯內,先走@Around注解的方法。然后是@Before注解的方法,然后這兩個都通過了,走核心代碼,核心代碼走完,無論核心有沒有返回值,都會走@After方法。然后如果程序無異常,正常返回就走@AfterReturn,有異常就走@AfterThrowing。

復雜的同一個方法被多個Aspect類攔截請參看博文:Spring AOP @Before @Around @After 等 advice 的執行順序

4 在aop中校驗不通過如何不讓程序進入核心代碼?

通過aop中注解的執行的先后順序我們知道,校驗發生在核心代碼前面的只剩下兩個——@Before,@Around。 
@Before : 這個注解只有在異常時才不會走核心方法——連接點。正常@Before無法阻止當前線程進入連接點。 
@Around : 這個注解在連接點前后執行。並且注解的方法傳入的ProceedingJionPoint 類中封裝的代理方法proceed()可以讓當前線程從aop方法轉到連接點——核心代碼方法。所以一般我們用這個注解,如果aop的安全校驗不通過,則不調用proceed()方法,就永遠不會進入連接點。 
除此外,要注意除了Around注解的方法可以傳ProceedingJionPoint 外,別的幾個都不能傳這個類。但是普通的數據類型是不限制的。注解的方法的返回值也不限制,可以自由限制。

參考博文: 
1.小曹學spring–基於@AspectJ和Schema的AOP 
2.徹底征服 Spring AOP 之 理論篇 
3.利用Spring AOP自定義注解解決日志和簽名校驗 
4.Spring AOP @Before @Around @After 等 advice 的執行順序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM