一. 捕獲方法調用
使用call(Signature)切入點。其語法:
pointcut <pointcut name>(
<any values to be picked up>) :
call (
<optional modifier> <return type> <class>.<method>(<paramater type>));
1. 在方法調用上觸發通知,其環境是調用類。
2. Signature可以包含通配符,用于選擇不同類和方法上的一系列連接點。
具有通配符的簽名 |
描述 |
* void MyClass.foo(int , float) |
無論修飾符是什么,都會捕獲方法上的連接點。也可以忽略修飾符的可見性來做到這一點。 |
void MyClass.foo(int , float) |
* * MyClass.foo(int , float) |
無論修飾符或返回類型是什么,都會捕獲方法上的連接點。 |
* MyClass.foo(int , float) |
* * *.foo(int , float) |
無論修飾符,返回類型或類是什么,都會捕獲方法上的連接點。 |
* *.foo(int , float) |
* * *.*(int , float) |
無論修飾符,返回類型,類或者方法是什么,都會捕獲方法上的連接點。 |
* * *.*(* , float) |
無論修飾符,返回類型,類,或者其中的參數包含任何內容并且后接一個浮點數的方法是什么,都會捕獲方法上的連接點。 |
* * *.*(* , ..) |
無論修飾符,返回類型,類,或者其中的參數包含至少一個單值并且后接任意數量的方法是什么,都會捕獲方法上的連接點。 |
* * *.*(..) |
無論修飾符,返回類型,類,或者其中有任意數量參數的方法是什么,都會捕獲方法上的連接點。 |
* *(..) |
* mypackage..*.*(..) |
捕獲mypackage包和子包內的任何方法上的連接點。 |
* MyClass+.*(..) |
捕獲MyClass和任何子類中任何方法上的連接點。 |
我們來看一個最簡單的例子:
package com.aspectj;


public aspect CallRecipe
{

/**//*
* Specifies calling advice whenever a mehtod
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name: foo
* Method Return Type: void
* Method Parameters: an int followed by a String
*/
pointcut callPointCut() : call(void MyClass.foo(int , String));
//Advice declaration

before() : callPointCut()
{
System.out.println("------------------- Aspect Advice Logic -------------------");
System.out.println("In the advice attached to the call point cut");
System.out.println("Actually executing before the point cut call");
System.out.println("But that's a recipe for Chapter 6!");
System.out.println("signature: " + thisJoinPoint.getStaticPart().getSignature());
System.out.println("Source Line: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("------------------------------------------");
}

}

這樣的一個方面可能執行下來的結果是這樣的:
------------------- Aspect Advice Logic -------------------
In the advice attached to the call point cut
Actually executing before the point cut call
But that's a recipe for Chapter 6!
signature: void com.aspectj.MyClass.foo(int, String)
Source Line: MyClass.java:10
-----------------------------------------------------------

foo(int , String)
這里有一個報告需要提醒一下。我們先運行如下代碼:
package com.aspectj;


public class Test extends MyClass
{

public void foo(int age , String name)
{
System.out.println("foo(int , String)");
}

public static void main(String[] args)
{
Test c = new Test();
c.foo(3 , "name");
}

}
Test.java是MyClass.java的子類,并重寫了foo(int , String)方法。按照Java正常的執行方法,運行Test.java是不會牽涉到任何方面的,但事實相反,callPointCut()通知還是會被執行。這就是AspectJ設計的比較妖怪的地方。對此,http://www.eecs.ucf.edu/~leavens/FOAL/papers-2004/barzilay-etal.pdf 有詳細的描述。有興趣的朋友可以研究一把。
/Files/zhengzhili/Call_and_Execution_Semantics_in_AspectJ.pdf
二. 捕獲方法調用上傳遞的參數值
可以使用call(Signature)和args([TypePatterns | Identifiers])切入點來捕獲對方法的調用,然后把需要的標識符綁定到方法的參數值上。
package com.aspectj;


public aspect CaptureCallPamaterRrecipe
{

/**//*
* Specifies calling advice whenever a mehtod
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name: foo
* Method Return Type: void
* Method Parameters: an int followed by a String
*/
pointcut captureCallPamaters(int value , String name) : call(void MyClass.foo(int , String)) && args(value , name);
//Advice declaration

before(int value , String name) : captureCallPamaters(value , name)
{
System.out.println("------------------- Aspect Advice Logic -------------------");
System.out.println("In the advice attached to the call point cut");
System.out.println("Captured int parameter on method: " + value);
System.out.println("Captured String parameter on method: " + name);
System.out.println("------------------------------------------");
}
}

上例中個人理解為兩次綁定過程。第一次captureCallPamaters通過args([Types | Identifiers])將foo方法的參數綁定到自己的參數上;第二次再把自己的參數綁定到before()上。也因此,1. pointcut captureCallPamaters(int value , String name) : call(void MyClass.foo(int , String)) && args(value , name); 中參數名必須一一對應;2.before(int value , String name) : captureCallPamaters(value , name) 中參數名也必須一一對應。而1和2之間的參數名則不需要一一對應。
三. 捕獲方法調用的目標
使用call(Signature)和targer([Type | Identifier])切入點來捕獲方法的調用,然后把單一標識符綁定到正在調用方法的對象上。
package com.aspectj;



public aspect CaptureCallTargetRecipe
{

/**//*
* Specifies calling advice whenever a method
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name: foo
* Method Return Type: void
* Method Parameters: an int followed by a String
*/
pointcut captureCallTarget(MyClass myObject) : call(void MyClass.foo(int , String)) && target(myObject);
//Advice declaration

before(MyClass myObject) : captureCallTarget(myObject)
{
System.out.println("------------------- Aspect Advice Logic -------------------");
System.out.println("In the advice attached to the call point cut");
System.out.println("Captured target object for the method call: " + myObject);
System.out.println("------------------------------------------");
}
}
四. 當執行一個方法時捕獲它
使用execution(Signature)切入點。其語法如下:
pointcut <pointcut name>(<any values to be picked up>) :
execution(<optional modifier> <return type> <class>.<method>(<paramater types>));
execution(Signature)切入點具有兩個關鍵特征:
1。觸發連接點的環境在目標類方法中。
2。Signature可以包含通配符,以選擇不同類和方法上的一系列連接點。
package com.aspectj;


public aspect ExecutionRecipe
{

/**//*
* Specifies calling advice whenever a method
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name: foo
* Method Return Type: void
* Method Parameters: an int followed by a String
*/
pointcut executionPointcut() : execution(void MyClass.foo(int , String));
//Advice declaration

before() : executionPointcut() && !within(ExecutionRecipe +)
{
System.out.println("------------------- Aspect Advice Logic -------------------");
System.out.println("In the advice picked by ExecutionRecipe");
System.out.println("signature: " + thisJoinPoint.getStaticPart().getSignature());
System.out.println("Source Line: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("------------------------------------------");
}
}

上述代碼和第一部分所使用的call(Signature)切入點相比,沒什么新的內容。但請注意是什么地方調用通知,以及它的環境是什么。即請特別關注thisJoinPoint.getStaticPart().getSourceLocation()的返回值。
五. 在執行方法時捕獲this引用的值
在執行期間捕獲方法時,想通過顯示Java的this引用所指向的對象,使之可以被通知使用,可以使用execute(Signature)和this(Type | Identifier)切入點來捕獲方法的執行,并把單一標識符綁定到方式執行期間this引用所指向的對象。
package com.aspectj;


public aspect CaptureThisReferenceRecipe
{

/**//*
* Specifies calling advice whenever a mehtod
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name: foo
* Method Return Type: void
* Method Parameters: an int followed by a String
*/
pointcut captureThisDuringExecution(MyClass myObject) :
execution(void MyClass.foo(int , String)) && this (myObject);
//Advice declaration

before(MyClass myObject) : captureThisDuringExecution(myObject)
{
System.out.println("------------------- Aspect Advice Logic -------------------");
System.out.println("In the advice attached to the execute point cut");
System.out.println("Captured this reference: " + myObject);
System.out.println("------------------------------------------");
}
}
