最爱Java

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

《AspectJ Cookbook》读书笔记十二: 捕获基于布尔或复合表达式的连接点

一.捕获何时连接点上的运行时条件评估为true
    使用if(Expression)语句来评估包含要比较的运行时变量的布尔表达式。if(Expression)语句的语法如下:
    pointcut <pointcut name>(<any values to be picked up>) : if(<Boolean expression>);

    if(Expression)语句有两个关键特征:
        1.if(Expression)切入点评估在运行时提供的变量,得到关于连接点是否应该触发相应通知的true或false结果。
        2.Expression可以由多个逻辑元素组成,包括展示的连接点环境,静态变以及其他切入点声明。


package com.aspectj;

public aspect IfRecipe {
     
// Define some variables for comparison
     private static final long realisticSalary=300001;

     
/**
      * Specifies calling advice if this is referencing an object of class MyClass
      * and the object has a realistic salary:
      
*/

     pointcut ifJoinPointThishasRealisticSalaryPointcut():
if(
             (thisJoinPoint.getThis() 
instanceof MyClass)
             
&& ((MyClass) thisJoinPoint.getThis()).getSalary() < realisticSalary
             
&& ((MyClass) thisJoinPoint.getThis()).getSalary() > 0)
         
&& !withincode(* MyClass.get*())
         
&& !execution(* MyClass.get*());
     
     
//Advice declaration
     
//This advice will be executed before the pointcut that picks it
        after() : ifJoinPointThishasRealisticSalaryPointcut() && !within(IfRecipe+{
            System.out.println(
"---------- Aspect Advice Logic ----------");
            System.out.println(
"In the advice picked by ifJoinPointThishasRealisticSalaryPointcut()");
            System.out.println(
"Join Point Kind" + thisJoinPoint.getKind());
            System.out.println(
"Executing object: " + thisJoinPoint.getThis());
            System.out.println(
"MyClass instance: " + ((MyClass) thisJoinPoint.getThis()).getName() + ":" + ((MyClass) thisJoinPoint.getThis()).getSalary());
            System.out.println(
"Signature: " + thisJoinPoint.getStaticPart().getSignature());
            System.out.println(
"Source Line: " + thisJoinPoint.getStaticPart().getSourceLocation());
            System.out.println(
"-----------------------------------------");        
        }
     
}



    if(Expression)语句允许定义是否应该把一份通知应用于特定连接点的条件逻辑。这个条件逻辑在运行时执行,并且在到达连接点那一刻必须工作在有效的类型上。
    例子中ifJoinPointThisHasRealisticSalaryPointcut()切入点中包含的条件逻辑指定在发生以下事件时,应该触发相应的after通知:
    1.执行对象是MyClass类型
    2.对象的salary属性小于realisticSalary常量
    3.对象的salary属性小于0
    4.当前连接点不在getSalary()方法内。通过使用通配符,连接点绝对不能出现在开始到达的MyClass类的任何方法中。
    
    可以使用AND(&&)运算符来逻辑地结合每个条件。前3个条件可以相当容易地理解成切入点布尔逻辑的一部分,但是最后一个条件更有趣一点。必须包含!withincode(* MyClass.get*())条件,以防止从通知内调用getSalary(),这反过来又会触发对通知的递归调用,并导致一个死循环。

二.使用逻辑AND(&&)结合切入点
    使用&&运算符。&& operator运算符的语法如下:
    pointcut <pointcut name>(<any values to be picked up>) : <pointcut declaation> && <pointcut declaration>


package com.aspectj;

public aspect LogicalAndRecipe {
    
/**
     * Specifies calling advice whenever a method 
     * matching the following rules gets called:
     * 
     * Class Name: MyClass
     * Method Name:Any Method
     * Method Return Type:Any Return Type
     * Method Parameters:Any Parameters
     
*/

    pointcut callAnyMethodOnMyClass():call(
* MyClass.* (..));
    
    
/**
     * Specifies calling advice whenever a method 
     * matching the following rules gets called:
     * 
     * Class Name: MyClass
     * Method Name:bar
     * Method Return Type:void
     * Method Parameters:None
     
*/

    pointcut callBarPointcut() : call(
void MyClass.bar());
    
    
/**
     * Specifies calling advice whenever a join points is 
     * encountered that would be picked by both pointcuts
     * specified:
     * 
     * Pointcut Name: callAyMethodOnMyClass
     * Pointcut Name:callBarPointcut
     * Method Return Type:void
     * Method Parameters:None
     
*/

    pointcut callIntersectionAnyAndBar():callAnyMethodOnMyClass() 
&& callBarPointcut();
    
    
//Advice declaration
    before():callAnyMethodOnMyClass()&&!within(LogicalAndRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callAnyMethodOnMyClass()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
//Advice declaration
    before():callBarPointcut()&&!within(LogicalAndRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callBarPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
//Advice declaration
    before():callIntersectionAnyAndBar()&&!within(LogicalAndRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callIntersectionAnyAndBar()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }
    
}


    在AspectJ环境中,当用&&运算符吧两个或多个简单的切入点结合进一步复合切入点时,被两个独立的切入点选择的连接点将触发复合切入点的关联通知。更简单地说,如果任一个简单切入点选择了任何一个连接点,那么整个复合切入点就不会选择这个连接点。
使用&&运算符结合切入点的次序还会影响复合切入点的解释方式。&&运算符的运行时分析是从左到右执行的。这意味着在检查候选连接点时,指示它不包含连接点的第一个切入点就是停止比较的地方。这对于Java中的&&运算符是成立的,并且当复合中的比较之一必须通过前一个条件加以保护时特别有用。

三. 使用逻辑OR(||)结合切入点
    使用||运算符。|| operator运算符的语法如下:
    pointcut <pointcut name>(<any values to be picked up>) : <pointcut declaation> || <pointcut declaration>

package com.aspectj;

public aspect LogicalOrRecipe {
    
/**
     * Specifies calling advice whenever a method 
     * matching the following rules gets called:
     * 
     * Class Name: MyClass
     * Method Name:foo
     * Method Return Type:void
     * Method Parameters:int and a String
     
*/

    pointcut callFooIntStringPointcut():call(
void MyClass.foo(int,String));
    
    
/**
     * Specifies calling advice whenever a method 
     * matching the following rules gets called:
     * 
     * Class Name: MyClass
     * Method Name:bar
     * Method Return Type:void
     * Method Parameters:None
     
*/

    pointcut callBarPointcut() : call(
void MyClass.bar());
    
    
/**
     * Specifies calling advice whenever a join points is 
     * encountered that would be picked by both pointcuts
     * specified:
     * 
     * Pointcut Name: callFooIntStringPointcut
     * Pointcut Name:callBarPointcut
     * Method Return Type:void
     * Method Parameters:None
     
*/

    pointcut callIntersectionFooOrBar():callFooIntStringPointcut() 
|| callBarPointcut();
    
    
//Advice declaration
    before():callFooIntStringPointcut()&&!within(LogicalOrRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callFooIntStringPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
//Advice declaration
    before():callBarPointcut()&&!within(LogicalOrRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callBarPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
//Advice declaration
    before():callIntersectionFooOrBar()&&!within(LogicalOrRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callIntersectionFooOrBar()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }
    
}



    在AspectJ语言中,如果连接点在使用逻辑OR结合进入复合切入点的任何成分切入点上启动通知,连接点就会触发那个通知。
    AspectJ中的||运算符还显示了短路行为,这个&&运算符相似且相反。

四.捕获所有未通过切入点声明指定的连接点
    使用一元!运算符,指定忽略那些通常由特定切入点捕获的连接点。!运算符的语法如下:
    pointcut <pointcut name>(<any values to be picked up>): !<pointcut declaation>


package com.aspectj;

public aspect LogicalNotRecipe {
    
/**
     * Specifies calling advice whenever a method 
     * matching NOT match the following rules:
     * 
     * Class Name: MyClass
     * Method Name:foo
     * Method Return Type:void
     * Method Parameters:int and a String
     
*/

    pointcut notCallPointcutFooIntString() : 
!call(void MyClass.foo(int,String));
    
    
//Advice declaration
    before():notCallPointcutFooIntString()&&!within(LogicalNotRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by callFooIntStringPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

}


五.声明匿名切入点
    匿名切入点是切入点声明的构件。在所有基于切入点的章节中都会用它,但是我们在这里更细致地关注匿名切入点。

package com.aspectj;

public aspect AnonymousPointcutRecipe {
    
/**
     * A pointcut declaration that is built up from one
     * anonymous pointcut:
     * 
     * Anonymous Pointcuts:call(void MyClass.foo(int,String))
     
*/

    pointcut singleAnonymousPointcut() : call(
void MyClass.foo(int,String));
    
    
/**
     * A pointcut declaration that is built up from two
     * anonymous pointcut:
     * 
     * Anonymous Pointcuts:call(void MyClass.foo(int,String))
     *                         call(void MyClass.foo(int,String))
     *                          !within(AnonymousPointcutRecipe+)
     
*/

    pointcut multipleAnonymousPointcut() : (
            call(
void MyClass.bar())
            
|| call(void MyClass.foo(int,String))
            
&& !within(AnonymousPointcutRecipe+));
    
    
/**
     * A pointcut declaration attached to the advice it will invoke,
     * built up from anonymous pointcut:
     * 
     * Anonymous Pointcuts:within(LogicalOrRecipe+)
     
*/

    
//Advice declaration
    before():singleAnonymousPointcut()&&!within(LogicalNotRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by singleanonymousPointcut and !within(AnonymousPointcutRecipe+)");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
/**
     * A pointcut declaration attached to the advice it will invoke,
     * built up from anonymous pointcut:
     * 
     * Anonymous Pointcuts:None
     
*/

    
//Advice declaration
    before():multipleAnonymousPointcut() {
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by multipleAnonymousPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }
    
}


    匿名切入点用于声明切入点,而不是检查特定的切入点类型。可以在命名切入点声明内匿名地声明切入点,或者通过把切入点直接附加到它们将调用的通知上来进行声明。

六.重用切入点
    声明一个切入点,可以在需要重用它的地方通过名称来引用它。

 

package com.aspectj;

public aspect PointcutReuseRecipe {
    
/**
     * A pointcut declaration that is to be used and reused:
     * Anonymous Pointcuts: call(void MyClass.foo(int,String))
     
*/

    pointcut foundationNamedPointcut():call(
void MyClass.foo(int,String));
    
    
/**
     * A pointcut declaration that is built up from two
     * pointcuts:
     * 
     * Anonymous Pointcuts:!within(AnonymousPointcutRecipe+)
     * Named Pointcuts:foundationNamedPointcut()
     
*/

    pointcut reuseNamedPointcut():foundationNamedPointcut()
&&!within(PointcutReuseRecipe+);
    
    
/**
     * A pointcut declaration attached to the advice it will invoke,
     * built up from simple named and anonymous pointcuts:
     * Anonymous Pointcut:!within(LogicOrRecipe+)
     * Named Pointcuts:foundationNamedPointcut();
     
*/

    before():foundationNamedPointcut()
&&!within(PointcutReuseRecipe+{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by foundationNamedPointcut and !within(PointcutReuseRecipe+)");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }

    
    
/**
     * A pointcut declaration attached to the advice it will invoke,
     * built up from complex pointcut built reusing other pointcut
     * declarations:
     * 
     * Named Pointcuts:reuseNamedPointcut();
     
*/

    before():reuseNamedPointcut() 
{
        System.out.println(
"---------- Aspect Advice Logic ----------");
        System.out.println(
"In the advice picked by reuseNamedPointcut()");
        System.out.println(
"Signature: " + thisJoinPoint.getSignature());
        System.out.println(
"Source Line: " + thisJoinPoint.getSourceLocation());
        System.out.println(
"-----------------------------------------");        
    }
    
    
    
}

 

posted on 2008-08-25 20:40 Brian 阅读(413) 评论(0)  编辑  收藏 所属分类: 《AspectJ Cookbook》读书笔记


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


网站导航:
博客园   IT新闻   Chat2DB   C++博客   博问  
 

公告


导航

<2008年8月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456

统计

常用链接

留言簿(4)

随笔分类

随笔档案

收藏夹

搜索

最新评论

阅读排行榜

评论排行榜