當前位置:編程學習大全網 - 編程語言 - Spring AOP 切點指示器

Spring AOP 切點指示器

Spring AOP借助AspectJ的切點表達式語言來定義Spring切面,下面是切點表達式中使用的指示器:

下面將通過壹些測試案例來說明以上各個切點指示器的用法。另外 execution 不作額外說明,因為比較常見。

定義壹個水果接口

定義壹個甜水果類

定義壹個產地接口

定義壹個水果重量接口

定義壹個蘋果重量類

定義壹個紅蘋果類

定義壹個果農類

使用的測試類

SweetFruit 實現 Fruit 接口。 RedApple 繼承 SweetFruit 並且實現 Origin 接口,並且關聯 FruitWeight 接口。 AppleWeight 實現 FruitWeight 接口。

定義包含 within 指示器的切面

測試用例

within 指示器用來限定連接點必須在確定的類型或包中 ,在上面的切面中定義了 Fruit 、 SweetFruit 、 RedApple 這三個類型,根據輸出發現只有 SweetFruit 、 RedApple 這兩個切面進行了攔截。這說明了 within 指示器只攔截確定的類型,也就是跟它的接口無關,定義什麽類型就攔截什麽類型。

定義包含 this 指示器的切面

測試用例

this 指示器用來限定連接點屬於給定類型的壹個實例(代理對象) ,從上面的輸出中可以看到, sweetFruit.print(); 被 this(...Fruit) 、 this(...SweetFruit) 攔截, redApple.print(); 和 redApple.printOrigin(); 被 this(...Fruit) 、 this(...SweetFruit) 、 this(...RedApple) 、 this(...Origin) 攔截。這說明了不管方法是來源於哪個接口或類( redApple.printOrigin(); 來源於 Origin 接口),只要代理對象的實例屬於 this 中所定義的類型,那麽這個方法就會被攔截。比如 sweetFruit 的代理對象既是 Fruit 的壹個實例,也是 SweetFruit 的壹個實例。 redApple 的代理對象分別屬於 Fruit 、 SweetFruit 、 RedApple 、 Origin 這四個類型的壹個實例。

註:我這邊的測試環境顯示AOP使用了CGLIB代理,也就是繼承代理,所以代理對象同屬以上接口或類,如果使用了JDK動態代理可能會產生不同的結果

定義包含 target 指示器的切面

測試用例

target 指示器用來限定連接點屬於給定類型的壹個實例(被代理對象) ,這個指示器的語義跟 this 指示器是很相似的,然後從上面的輸出來看它們也是壹樣的(除了指示器不同)。但是它們有壹個重要的區別, this 中的實例指的是代理對象,而 target 中的實例指的是被代理對象。

定義包含 args 指示器的切面 ,上面的切面表達式中額外定義了 within 指示器,這個主要是為了縮小 args 的使用範圍。如果不加,Spring AOP會嘗試去代理所有符合條件的對象,但是有些對象的訪問會有限制,導致啟動異常。這個也提醒我們使用AOP時必須要明確指定使用範圍,否則會造成不可預料的錯誤。

測試用例 ,回顧壹下之前定義的三個 printPrice 方法:

args 指示器用來限定連接點,也就是方法執行時它的參數屬於給定類型的壹個實例 ,從上面的輸出來看,只有 public void printPrice(Integer price, String mesg) 這個方法被攔截,因為只有它符合條件。如果我們將定義改為 public void printPrice(String mesg,Integer price ) ,結果如下:

也就是說 args 指示器不但對參數類型有要求,而且還會對參數個數、定義順序有要求。

定義包含 @target 指示器的切面

測試用例 ,然後回顧壹下之前定義的 RedApple 這個類上所註解的 @Validated :

現在刪除 RedApple 上的 @Validated 註解,將這個註解放到 SweetFruit 上,輸出如下:

重復以上步驟,將 @Validated 註解放到 Fruit 接口上,輸出如下:

@target 用來限定連接點屬於壹個執行對象(被代理對象)所屬的擁有給定註解的類。 雖然 @target 和 target 名稱相似,但是它們用法是完全不同的,前者針對註解,後置針對類型。另外從上面的輸出可以看出 @target 限定在壹個執行對象的所屬類,與它的父類接口無關。

定義包含 @within 指示器的切面

測試用例 ,然後註意 redApple.print(11); 它是定義在 SweetFruit 類中

現在刪除 RedApple 上的 @Validated 註解,將這個註解放到 SweetFruit 上,輸出如下:

重復以上步驟,將 @Validated 註解放到 Fruit 接口上,輸出如下:

@within 用來限定連接點屬於擁有給定註解的類型中。 從上面的輸出可以看出, @target 針對執行對象所屬的類,而 @within 針對執行對象所屬的類型。另外所執行的方法必須屬於擁有給定註解的類型中,比如 redApple.print(); 被重寫在 RedApple 類中, redApple.print(11); 被定義在 SweetFruit 類中,當這兩個類擁有指定註解後方法執行時才會被攔截。最後需要註意的是 @within 和 within 只是名稱接近,實際使用效果是不同的。

定義包含 @args 指示器的切面

測試用例 ,回顧壹下在 RedApple 中定義的方法以及 FruitWeight 接口的定義:

現在刪除 AppleWeight 上的 @JsonDeserialize 註解,將這個註解放到 FruitWeight 上,輸出如下:

現在將 @JsonDeserialize 註解放到 AppleWeight 上,並且再定義壹個繼承了 AppleWeight 的子類:

測試用例

@args 用來限定連接點,方法執行時傳遞的參數的運行時類型擁有給定註解。 根據以上的輸出以及 @args 的定義,這個給定的註解要麽定義在方法參數的類型本身上,那麽定義在的它的實現類上。比如 RedAppleWeight 它雖然繼承了 AppleWeight (擁有指定註解),但是它本身沒有指定註解,並且當 FruitWeight 也沒有指定註解時,相關方法不會被攔截。

定義包含 @annotation 指示器的切面

測試用例 ,回顧壹下 FruitFarmer 的定義:

現在刪除 print() 上的 @JsonSerialize 註解,輸出如下:

@annotation 用來限定連接點的方法擁有給定註解。 這個指示器比較容易理解,就是目標方法上擁有給定註解就可以了。

參考資源

  • 上一篇:網絡編程先鋒
  • 下一篇:什麽是SMT,什麽是SMD?
  • copyright 2024編程學習大全網