一.訪問類成員
package com.aspectj;


public privileged aspect MemberAccessRecipe
{

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

after(MyClass myClass):executionOfFooPointCut() && this(myClass)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Accessing the set(float) member of the MyClass object");
System.out.println("Privileged access not required for this method call as it is public");
myClass.setF(2.0f);
System.out.println("Using the privileged aspect access to the private f member variable");
System.out.println("The current value of f is: ");
System.out.println(myClass.f);
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Line: " + thisJoinPoint.getSourceLocation());
System.out.println("-----------------------------------------");
}
}

通過使用this(Identifier)切入點定義,使得MyClass類的對象可供通知使用。this(Identifier)切入點定義有效地把通知展示給被觸發連接點處的this引用指向的對象。從通知內調用setF(float)方法,并顯示對MyClass對象的公共方法的訪問。為了獲得對MyClass.f私有屬性的訪問,方面不得不對其結構執行一些額外的更改。方面嘗試通過直接訪問私有成員來破快封裝性,因此,必須把方面聲明為privileged,因為它正在提交潛在的侵入動作。
AspectJ提供了privieged關鍵字,它用在方面需要完全不受限制地訪問類的地方,包括那些未在類的公共接口上聲明的成員變量和方法。方面的privileged狀態應該充當一個警告,在對方面或者它所應用的類執行任何更改時,必須當心這個警告,因為這些更改可能潛在地在整個應用程序中引發其他問題。
二.訪問連接點環境
AspectJ提供了thisJoinPoint變量,用于展示this連接點環境。如果可以靜態地訪問正在訪問的環境,那么thisJoinPointStaticPart也是有用的。
package com.aspectj;


public aspect ThisJoinPointRecipe
{

/** *//**
* Specifies calling advice whenever a method
* matching the following rules gets executed:
*
* 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()&&!within(ThisJoinPointRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Exercising the static parts of AspectJ 1.1.1 thisJoinPoint");
System.out.println("Source Line: " + thisJoinPointStaticPart.getSourceLocation());
System.out.println("JoinPoint Kind: " + thisJoinPointStaticPart.getKind());
System.out.println("Simple toString: " + thisJoinPointStaticPart.toString());
System.out.println("Simple toShortString: " + thisJoinPointStaticPart.toShortString());
System.out.println("Simple toLongString: " + thisJoinPointStaticPart.toLongString());
System.out.println("Exercising the join point generic signature of AspectJ 1.1.1 thisJoinPoint");
System.out.println("Signature name:" + thisJoinPointStaticPart.getSignature().getName());
System.out.println("Signature declaring type:" + thisJoinPointStaticPart.getSignature().getDeclaringType());
System.out.println("-----------------------------------------");
}

before():callPointCut()&&!within(ThisJoinPointRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Exercising the dynamic parts of AspectJ 1.1.1 thisJoinPoint");
System.out.println("Get the this reference: " + thisJoinPoint.getThis());
System.out.println("Getting the Target: " + thisJoinPoint.getTarget());
System.out.println("Join Point Arguments:");
Object[] args = thisJoinPoint.getArgs();

for (int count = 0; count < args.length ; count++)
{
System.out.println(args[count]);
}
System.out.println("-----------------------------------------");
}
}

thisJoinPoint變量包含關于觸發連接點的靜態和動態環境信息。靜態環境信息包含可以在編譯和織入時決定的任何信息。動態連接點環境信息則只能在運行時填充,因為它依賴于連接點環境實際的運行時狀態。
三.在連接點之前執行通知
使用before()類型的通知
package com.aspectj;


public aspect BeforeAdviceRecipe
{

/** *//**
* Specifies calling advice whenever a method
* matching the following rules gets executed:
*
* 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()&&!within(BeforeAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
}
}

四.在連接點周圍執行通知
使用around()類型的通知。
package com.aspectj;


public aspect AroundAdviceRecipe
{

/** *//**
* 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 callFooPointCut() : call(int MyClass.foo());

/** *//**
* Specifies calling advice whenever a method
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name:bar2
* Method Return Type:int
* Method Parameters:an int
*/
pointcut callBarPointCut(int value) : call(int MyClass.bar(int)) && args(value);

/** *//**
* Specifies calling advice whenever a method
* matching the following rules gets called:
*
* Class Name: MyClass
* Method Name:baz
* Method Return Type:int
* Method Parameters:
*/
pointcut callBazPointCut() : call(int MyClass.baz());
//Advice declaration
//This advice will be executed before the pointcut that picks it

int around() : callFooPointCut()&& !within(AroundAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
return proceed();
}
//Advice declaration
//This advice will be executed before the pointcut that picks it

int around(int value):callBarPointCut(value)&&!within(AroundAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
return proceed(value);
}
//Advice declaration
//This advice will be executed before the pointcut that picks it

int around(int value):callBarPointCut(value)&&!within(AroundAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
return proceed(value);
}
//Advice declaration
//This advice will be executed before the pointcut that picks it

int around() : callBazPointCut() && !within(AroundAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Signature: " + thisJoinPoint.getSignature());
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
return 200;
}
}

around()通知是一種強大的構造,它指示AspectJ應該運行通知,而不是指示連接點觸發它。這允許重寫應用程序中存在的原始邏輯。這說明了around()通知,可以依據是否從around()通知塊內發起proceed()調用,來被動或主動地應用這個通知。
proceed()調用指示around()通知應該繼續執行原始連接點邏輯,并傳遞原來可用的任何值。
在示例中,第一份通知沒有參數需要傳遞;第二份通知傳遞了一個與原始值完全不同的值;第三份通知則完全返回了一個不同的值。
around()通知必須具有指定的返回值,但是如果不需要值,那么可以是void。
五.在連接點之后無條件執行通知
使用after()類型的通知
package com.aspectj;


public aspect AfterAdviceRecipe
{

/** *//**
* 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 callPointCut() : call(void MyClass.foo(int,String));
//Advice declaration

after():callPointCut()&&!within(AfterAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
}
}

六.僅在從連接點正常返回之后才執行通知
使用after() returning或after() returning(<ReturnType> <Identifier>)類型的通知
package com.aspectj;


public aspect AfterReturningAdviceRecipe
{

/** *//**
* 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 callPointCut():call(void MyClass.foo(int));
//Advice declaration

after() returning:callPointCut()&&!within(AfterReturningAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
}
}

package com.aspectj;


public aspect AfterReturningValueAdviceRecipe
{

/** *//**
* 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 callPointCut():call(void MyClass.foo(int));
//Advice declaration

after() returning(Object value):callPointCut()&&!within(AfterReturningAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("Value being returned: " + value);
System.out.println("-----------------------------------------");
}
}

使用after() returning(<ReturnType> <Identifier>)通知訪問基本類型的一個有趣作用是:必須把基本的int值裝箱進Integer類的一個實例中,以傳遞給通知。當通知期待的返回類型是Object類型時,并且如果返回值是基本類型,AspectJ將自動并且透明地把基本值裝箱進其對應的Java類中。around()形式的通知也可以使用這種自動和透明的裝箱行為,其中會期待Object類型的值,并且將從通知傳遞基本值或將基本值傳遞給通知。
與正常的ater()相比,after() returning形式的通知提供了更精細的過濾器。
七.僅當連接點中引發了一個異常之后才執行通知
使用after() throwing或after() throwing(<ExceptionType> <Identifier>)類型的通知。
package com.aspectj;


public aspect AfterThrowingAdviceRecipe
{

/** *//**
* 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 callPointCut():call(void MyClass.foo(int));
//Advice declaration

after() throwing:callPointCut()&&!within(AfterThrowingAdviceRecipe+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("Source Location: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
}
}

八.控制通知優先級
如果把位于不同方面中的相同類型的通知應用同一連接點,則可以使用declare precedence通知。其語法如下:
declare precedence:TypePattern,TypePattern,...;
package com.aspectj;


public aspect AspectA
{
// Declare precedence rules
declare precedence:AspectA,AspectB;


/** *//**
* 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 callPointCut():call(void MyClass.foo(int,String));

// Advice declaration

before():callPointCut()&&!within(AspectA+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("In the advice of AspectA");
System.out.println("Target: " + thisJoinPoint.getTarget());
System.out.println("This: " + thisJoinPoint.getThis());
System.out.println("Aspect Instance: " + AspectA.aspectOf());
System.out.println("-----------------------------------------");
}
}

在declare precedence語句中使用TypePattern來指定不同的方面,以及他們的顯式次序。可以使用通配符來指定TypePatterns,以根據需要為特定的方面集合或方面的整個包指示優先級。
當把一個方面中的兩個相同類型的通知塊應用于同一個連接點時,declare precedence語句就沒有意義了。為了處理這種情況,AspectJ基于方面聲明內通知的類型和位置,來應用隱式的優先級次序:
- 按在方面中聲明before()和around()通知類型的次序,來應用他們隱式優先級規則。如果把同一方面的兩個before()通知塊應用于同一個連接點,那么聲明第一個塊將具有最高的優先級,而最后一個則最低。
- 而after()、aftr() returning和around() throwing通知類型的隱式優先級則于before()相反。
九.通知方面
package com.aspectj;


public aspect AdviseAspectRecipe
{

/** *//**
* 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 callPointCut():call(void MyClass.foo(int,String));
//Advice declaration

before() : callPointCut()&&within(AdvisedAspect+)
{
System.out.println("---------- Aspect Advice Logic ----------");
System.out.println("In the advice attached to the call point cut");
System.out.println("Signature: " + thisJoinPoint.getStaticPart().getSignature());
System.out.println("Source Line: " + thisJoinPoint.getStaticPart().getSourceLocation());
System.out.println("-----------------------------------------");
}
}
