在這之前我們已經介紹了AOP的基本功能和概念,那么當AOP集成到spring則會發生改變。
Spring AOP 中的Joinpoint:
之前提高了很多Joinpoint的類型,但是在spring中則只會有方法級別的Joinpoint,像構造方法,字段的調用都沒適配。原因是Spring框架一直追求輕量級和高效,而僅僅采用方法級的Joinpoint即可滿足百分之八十的需求。同時如果采用類中的屬性級別的Joinpoint則會破壞對象的封裝。如果需求非常特殊超過了拿百分之八十的需求那么不妨可以使用AspectJ的方式。
Spring AOP 中的Pointcut:
Spring中以接口定義Pointcut作為其最頂層的抽象接口,該接口定義了兩個方法用來幫助捕獲系統中相應的Joinpoint
兩個方法的ClassFilter和MethodMatcher分別是用來匹配將執行織入操作的對象以及相應的方法。
也就是說ClassFilter是對于類型對象的匹配而MethodMatcher則是對于方法級別的匹配,
MethodMatcher的復雜度相比于ClassFilter要高。原因是ClassFilter僅僅只需要匹配類型即可而MethodMatcher則可能需要匹配方法名稱或者方法名稱+參數
因此對于MethodMatcher則有多個方法進行匹配
有兩個matches的方法,而這兩個方法的分界線就是isRuntime方法。在對具體的方法進行攔截的時候,可以忽略每次方法執行的時候調用者傳入的參數,也可以每次都檢查這些方法調用參數,以強化攔截條件,都是與isRuntime的返回值有關如果返回值為false則會觸發第一個matches方法這種屬于不會考慮具體方法的參數,而如果返回結果為true則會調用第二個matches方法表示采用參數的匹配
將這兩個MethodMatcher類型分為StaticMethodMatcher和DynamicMethodMatcher類型。StaticMethodMatcher類型則是無參數檢查,這種無需參數檢查的類型可以緩存在框架內部,同時性能比較出色,對于DynamicMethodMatcher類型是參數檢查,因此不會進行緩存操作,同時性能上相比StaticMethodMatcher則是損耗很大。
常見的PointCut
下面我們來介紹幾個常見的PointCut
NameMatchMethodPointcut:
這個是最簡單的Pointcut實現,屬于StaticMethodMatcher的子類,可以根據自身指定的一組方法名稱與Joinpoint處的方法的名稱進行匹配
JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut
StaticMethodMatcher的子類有一個專門基于正則表達式的實現分支,而JdkRegexpMethodPointcut和Perl5RegexpMethodPointcut則是不同類型的正則表達式的具體實現。
AnnotationMatchingPointcut
根據目標對象中是否存在指定類型的注解來匹配Joinpoint,要使用該類型的Pointcut首先需要聲明相應的注解。
CompossablePointcut
提供邏輯運算功能,而ComposablePointcut就是Spring AOP提供的可以進行Pointcut邏輯運算的Pointcut實現。它可以實現Pointcut之間的并以及交運算。
ControlFlowPointcut
ControlFlowPointcut則是最特殊的Pointcut類型,在理解和使用上都需要我們多付出點腦細胞,ControlFlowPointcut匹配程序的調用流程,不是對某個方法執行所在的Joinpoint處的單一特征進行匹配。通過ControlFlowPointcut我們可以實現指定只有當某個類的方法在被執行的類對象調用的時候才會對方法進行攔截處理
Spring AOP中的Advice
Advice實現了將被織入到Pointcut規定的Joinpoint處的橫切邏輯。在spring中,advice按照其自身實例能否在目標對象類的所有實例中共享這一標準,可以劃分為兩大類,即per-class類型的advice和per-instance類型的advice。
per-class類型的Advice
per-class類型的Advice是指該類型的實例可以在目標對象類的所有實例之間進行共享,這種類型的Advice只是提供方法攔截的功能,不會為目標對象類保存任何狀態或者添加新的特性。
那么per-class有著以下幾種類型
Before advice
實現的橫切邏輯將在相應的Joinpoint之前執行,在Before advice執行完成之后,程序執行流程將從Joinpoint處繼續執行,所以Before Advice通常不會打斷程序執行的流程,但是如果有必要,也可以通過拋出相應異常的形式中斷程序流程
ThrowsAdvice
throwsAdvice通常用于對系統重特定的異常情況的監控,以統一的方式對所發生的異常進行處理,一旦捕獲到異常,需要馬上以某種方式通知系統的監控或者運營人員
AfterReturningAdvice
通過spring的AfterReturningAdvice,我們可以訪問當前joinpoint的方法返回值,方法,方法參數以及所在的目標對象
Around Advice
Spring AOP沒有提供AfterAdvice,使得我們沒有一個合適的advice類型來承載類似于系統資源清除之類的橫切邏輯。Spring AOP的AfterReturningAdvice不能更改Joinpoint所在方法的返回值,使得我們在方法正常返回后無法對其進行更多的敢于。有了Around Advice則可以解決這個問題
per-instance類型的Advice
在Spring AOP當中只有一個類型的per-instance型Advice就是Introduction
Introduction
Introduction允許你在不修改目標類代碼的情況下,為其動態添加新的接口和實現。這相當于在運行時為目標對象 “混入” 額外的行為,使其具備原本沒有的功能。
// 定義新接口
public interface Monitorable {void setMonitorActive(boolean active);boolean isMonitorActive();
}// 實現接口和 IntroductionInterceptor
public class MonitorInterceptor implements MethodInterceptor, Monitorable {private boolean monitorActive = false;@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {if (monitorActive && invocation.getMethod().getName().startsWith("get")) {System.out.println("Monitoring: " + invocation.getMethod().getName());}return invocation.proceed();}@Overridepublic void setMonitorActive(boolean active) {this.monitorActive = active;}@Overridepublic boolean isMonitorActive() {return monitorActive;}
}// 創建 IntroductionAdvisor
public class MonitorAdvisor extends DefaultIntroductionAdvisor {public MonitorAdvisor() {super(new MonitorInterceptor(), Monitorable.class);}
}
增強類型 | 作用 | 是否改變類結構 |
---|---|---|
Before/After | 在方法前后添加行為 | 否 |
Around | 環繞方法執行,完全控制調用過程 | 否 |
Introduction | 為目標對象添加新接口和實現 | 是(運行時) |