`
小嘴冰凉
  • 浏览: 447293 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

AspectJ学习笔记之Pointcut

阅读更多
http://dev.csdn.net/author/CenturyMagus/index.html

该文是我读AspectJ in Action时的一些学习笔记和自己的一些学习总结,当时是用英文记下的(因为书是英文的嘛,嘿嘿,而且个人认为看英文文档更能理解的透彻一些,毕竟是作者的原话嘛),现在放到网上和大家共享,并翻译成中文,如果哪处我翻译的不够恰当,理解的不够准确,请各位看英文部分以获得更准确的信息并给予我指正。(ah011@163.com)

 

Pointcuts

public  pointcut  accountOperations :call(*Account.*(..))

这是定义了一个pointcut,其中:

public 是access specifer

pointcut 是keyword

accountOperations 是poincut name

call是pointcut type;;pointcut能与其他pointcut通过或(||)、与(&&)以及非(!)操作符联合

Account是signature

 

l         常用pointcut类型

1)      call

2)      execution

3)      target

4)      args

5)      within

6)      cflow

 

l         基本概念

如果对上面的概念不是特别了解没有关系,下面就介绍一些基本的概念:

Joint Point

A join point is an identifiable point in the execution of a program. It could be a call to a method or an assignment to a member of an object.

join point 是程序执行过程中可以被识别的点。它可以是对一个函数的调用或是对象的一个属性。(注:spring的AOP只能做到对函数调用的拦截)

例子:

Public class Account

{

 void credit(float amount)

{

       _balance += amount;

}

}

这个例子中的join point包括Account类中执行credit()方法和对_balance的操作。

 

Pointcut

A pointcut is a program construct that selects join points and collects context at those points. For example, a pointcut can select a join point that is a call to a method, and it could also capture the method’s context, such as the target object on which the method was called and the method’s arguments.

We can write a pointcut that will capture the execution of the credit() method in the Account class shown earlier:

execution(void Account.credit(float))

To understand the difference between a join point and pointcut, think of pointcuts as specifying the weaving rules and join points as situations satisfying those rules.

 

pointcut 是一种程序结构,它用于选取join point并收集这些point的上下文信息。举例来说,pointcut可以是一个调用方法的join point,并且它能捕获这个方法的上下文信息,例如调用这个方法的目标对象和该方法的属性。

我们可以写一个pointcut,它将可以捕获前面Account类中credit()方法的执行:

execution(void Account.credit(float))

 

要想理解join point和pointcut的不同,可以把pointcut想成明确了织入的规则,而join point则声明了符合这些规则的情况(即什么情况下运用织入的规则)。

 

l          笔记要点

1.        In AspectJ, pointcut can be either anonymous or named.

aspectj中,poincut可以是匿名的,也可以是命名的。

 

2.        Notice that the name of the pointcut is at the left of the colon and pointcut definition is at the right. The pointcut definition is syntax that identifies the join points where you want to insert some action.

注意,pointcut的名字应位于冒号的左侧,而pointcut的定义在冒号的右侧。point cut的定义明确了你想在哪个join point插入一些动作。

 

3.        Three wildcard notations are available in AspectJ:

1)      * denotes any number of characters expect the period.

2)      .. denotes any number of characters including any number of period.

3)      + denotes any subclass or subinerface of a given type.

Example:

*Account       Types with a name ending with Account such as SavingsAccout and CheckingAccount

java.*.Data    Types Data in any direct subpackages of the java package, such as java.util.Data and java.sql.Data.

java..*           Any type inside the java package or all of its direct subpackage, such as java.awt and java.util, as well as indirect subpackages such as java.awt.event and java.util.logging

 

以下是AspectJ中的三个通配符:

1)      * 表示匹配任意数量的字符,除了句号(.)

2)      .. 表示比配包含句号在内的任意数量的字符。

3)      + 表示比配任意给定的类型的子类和子接口。

例子:

*Account       匹配以Account结尾的类型名,例如SavingsAccout和 

CheckingAccount

java.*.Data  匹配java包下的直接子包下的Data类型,例如java.util.Data和java.sql.Data(注:但不能是java.a.b.Data, 因为*不能包含句号嘛)

java..*           匹配java包下任意类型或者其所有直接子包,例如java.awt和java.util,也可匹配其非直接子包,例如java.awt.event和java.util.logging 

 

4.        Please note that in method signatures, the wildcard .. used to denote any type and number of arguments taken by a method.

Example:

*java.io.Reader.read(char[],.. )

Any read() method in the Reader class irrespective of type and number of arguments to the method as long as the first argument type is char[]. In this case, it will mach read(char[])  and  read(char[], int, int), but not read().

请注意在method signatures中,通配符..被用于表示匹配包含任意类型和任意数量的参数的方法。

例子:

*java.io.Reader.read(char[],.. )

Reader类中的任何read()方法,无论参数是什么类型,数量如何,只要其首参数是char[]类型,就可以匹配。这种情况下,它可以匹配read(char[]),也可以匹配read(char[], int, int),但不能匹配read()。

 

5.        The execution join point is on the method body itself.

执行类型的join point是方法体本身。

Example:


In this code snippet, the point for the execution of the debit() method is the whole method body. This means that we can write advice for this join point to the applied before, after, and around the body.

在这个程序小片段里,debit()方法的执行类型joint point是整个方法体。这意味着我们可以为它写符合要求的advice(通知),包括before、after、around。(注:关于advice,将在下一篇中介绍)

6.        The method call join point occurs at the place where this method is being invoked.

方法调用的join point放生在方法被引用的地方。

Example:

Account account = …...;

account.debit(100);  //debit() method call join point

 

Note that the code that forms the arguments is not a part of the join point. For example, if the debit() method is called in the statement account.debit(Currend.round(100.2345)), the call Current.round(100.2345) is not part of the debit() method call join point.

注意,代码形式的参数不是call join point的一部分。例如如果debit()方法以如下形式调用,account.debit(Currend.round(100.2345)),那么Current.round(100.2345)不是其method call join point的一部分。

 

7.        execution 和call join point 的区别

我的理解是:

1)  在你想针对某个方法进行某些advice的织入时,应该用execution,即当想在某个方法的方法体之前,之后,之中织入某些advice时使用。

Example:


在这段代码中,如果想在debit()的方法体,即


之前、之后、之中织入一些advice时使用。

2)  而call是想在调用某个方法的地方之前、之后织入某些advice时使用的。

Example:

Account account = …...;

account.debit(100);  //即在句前、后加advice时使用。

 

8.        Execution Object Pointcuts (this和target)

1)      These pointcuts match the join points based on the types of the objects at execution time.

这种pointcut用于在运行期匹配对象的类型。

2)      In addition to matching the join points, these pointcuts are used to collect the context at the specified join point.

另外,这种pointcut可以用于收集join point附近的上下文信息。

3)      The this() pointcut takes the form this(Type or ObjectIdentifier); it matches all join points that have a this object associated with them that is of the specified type or the specified ObjectIdentifier’s type. In other words, if you specify Type, it will match the join points where the expression this instanceof <Type> is true. The form of this pointcut that specifies ObjectIdentifier is used to collect the this object. If you need to match without collecting context, you will use the form that uses Type, but if you need to collect the context, you will use the form that uses ObjectIdentifier.

this() 型pointcut的基本形式为this(Type or ObjectIdentifier);它匹配所有有this对象的pointcut,而这些pointcut就是已声明的类型或对象标识符的类型。换句话说就是,如果你声明了Type,当表达式this instanceof <Type>为真时将匹配。声明为ObjectIdentifier的pointcut将用于收集this对象的上下文信息。如果你想只匹配而不收集上下文,可以使用Type,反之则使用ObjectIdentifier

4)      The target() pointcut is similar to the this () pointcut. The target() pointcut is normally used with a method call join point.

target() pointcut 和this() pointcut类似。target() pointcut 一般和call join point 搭配使用。

5)      Example:

this(Account)        All join points where this is instanceof Account. This will match all join points like methods calls and field assignments where the current execution object is Account, or its subclass, for example, SavingsAccount.

target(Account)     All the join points where the object on which the method called is instanceof Account. This will match all join points where the target object is Account, or its subclass, for example, SavingsAccount.

6)      target 匹配的是哪个对象调用了某方法

Example:

ResgisterBuiness rb = new ResgisterBuiness();

forwardName = rb.doRegister(mapping.form);

对于doRegister方法来说,rb就是target

 

9.        Lexical-structure based pointcuts

1)      A lexical scope is a segment of source code. The within() pointcuts take the form of within(TypePattern) and are used to capture all the join points within the body of the specified classes and aspects, as well as any nested classes. The withincode() pointcuts take the form of either withincode(MethodSignature) or withincode(ConstrutorSignature) and are used to capture all the join points inside a lexical structure of constructor or a method, including any local classes in them.

lexical scope就是一个代码段。within() pointcut 形式是within(TypePattern) ,用来捕获声明的类、方面、还有内部类体的所有join point。withincode() pointcut的形式是withincode(MethodSignature)和withincode(ConstrutorSignature),用于捕获构造函数或方法的词法结构内的所有join point,包括它们内部的任何local classes。

2)      One common usage of the within() pointcut is to exclude the join points in the aspect itself. For example, the following pointcut excludes the join point corresponding to the calls to all print methods in the java.io.PrintStream class that occur inside the TraceAspect itself:

call(*java.io.PrintStream.print*(..)) && ! within(TraceAspect)

 

3)      this 和within的作用差不多,以下为不同点:

<1> within包含内部类,但不包含子类

<2> this包含子类,但不包含内部类

 

10.    Argument pointcuts

These pointcuts capture join points based on the argument type of a join point. Similar to execution object pointcuts these pointcuts can be used to capture the context.

Example:

args(String, .. , int)        All the join points in all methods where the first argument is of type String and last argument is of type int.

匹配所有以String为第一个参数类型,以int为最后一个参数类型的方法。

 

11.    Control-flow based pointcuts

1)      The control flow of a join point defines the flow of the program instructions that occur as a result of the invocation of the join point.

join point的控制流定义了程序指令的流程,以join point调用的结果的形式出现。

2)      For example, the Account.debit() method calls Account.getBalance() as a part of its execution; the call and the excution of Account.getBalance() is said to have occurred in the Account.debit() method’s control flow, and therefore it has occurred in the control flow of the join point for the method.

例如:Account.debit()方法调用Account.getBalance()作为它执行的一部分;对Account.getBalance()进行call和execution操作都可以认为是发生在Account.debit()方法的控制流内,所以就是发生在join point的控制流内。

3)      以下是我经过实验后的一些理解:

接着上面的例子,如果Account.getBalance()中又调用了另一个方法,例如abc(),那么abc()的join point也属于Account.debit()的control-flow,也即不管经过了多少层的调用关系,用control-flow pointcut都可以判断出某个join point是否属于一个control-flow;这一点上和within()又有一定的区别,within只能判别出join point是否在一个代码块中出现过,即只能表示一层关系。

4)      cflow(call(*Account.debit(..)) 任何在debit() control-flow中的join point都将被捕获,包括对debit()自身的call(即cflow()被用在了debit()自己的pointcut时的情况)

cflowbelow(call(*Account.debit(..)) 不包括对debit()自身的call




分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics