最爱Java

书山有路勤为径,学海无涯苦作舟

《AspectJ Cookbook》读书笔记四: 捕获方法上的连接点

一. 捕获方法调用
        
使用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(
"------------------------------------------");        
    }

}

posted on 2008-07-03 22:17 Brian 阅读(1508) 评论(2)  编辑  收藏 所属分类: 《AspectJ Cookbook》读书笔记

评论

# re: 《AspectJ Cookbook》读书笔记四: 捕获方法上的连接点 2008-07-03 23:05 lvq810

怎么没三?  回复  更多评论   

# re: 《AspectJ Cookbook》读书笔记四: 捕获方法上的连接点[未登录] 2008-07-04 00:37 呵呵

学习了  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

公告


导航

<2008年7月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

统计

常用链接

留言簿(4)

随笔分类

随笔档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜