命名切点
在前面所举的例子中,切点直接声明在增强方法处,这种切点声明方式称为匿名切点,匿名切点只能在声明处使用。如果希望在其它地方重用一个切点,我们可以通过@Pointcut注解以及切面类方法对切点进行命名,以下是一个具体的实例:
代码清单 8 TestNamePointcut
@Pointcut("execution(* greetTo(..)))") ②通过注解方法greetTo()对该切点进行命名,方法可视域package com.baobaotao.aspectj.advanced;
import org.aspectj.lang.annotation.Pointcut;
public class TestNamePointcut ...{
@Pointcut("within(com.baobaotao.*)") ①通过注解方法inPackage()对该切点进行命名,方法可视域
修饰符为private,表明该命名切点只能在本切面类中使用。
private void inPackage()...{}
修饰符为protected,表明该命名切点可以在当前包中的切面
类、子切面类中中使用。
protected void greetTo(){}
@Pointcut("inPackage() and greetTo()") ③引用命名切点定义的切点,本切点也是命名切点,
它对应的可视域为public
public void inPkgGreetTo()...{}
}
我们在代码清单 8中定义了3个命名切点,命名切点的使用类方法作为切点的名称,此外方法的访问修饰符还控制了切点的可引用性,这种可引用性和类方法的可访问性相同,如private的切点只能在本类中引用,public的切点可以在任何类中引用。命名切点仅利用方法名及访问修饰符的信息,所以习惯上,方法的返回类型为void,并且方法体为空。我们可以通过下图更直观地了解命名切点的结构:

图 8 命名切点结构
在③处,inPkgGreetTo()的切点引用了同类中的greetTo()切点,而inPkgGreetTo()切点可以被任何类引用。你还可以扩展TestNamePointcut类,通过类的继承关系定义更多的切点。
命名切点定义好后,就可以在定义切面时通过名称引用切点,请看下面的实例:
package com.baobaotao.aspectj.advanced;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class TestAspect ...{
@Before("TestNamePointcut.inPkgGreetTo()") ①
public void pkgGreetTo()...{
System.out.println("--pkgGreetTo() executed!--");
}
@Before("!target(com.baobaotao.NaiveWaiter) && TestNamePointcut.inPkgGreetTo()") ②
public void pkgGreetToNotNaiveWaiter()...{
System.out.println("--pkgGreetToNotNaiveWaiter() executed!--");
}
}
在①处,我们引用了TestNamePointcut.inPkgGreetTo()切点,而在②处,我们在复合运算中使用了命名切点。