我们在前面的文章中,在一个切面类中定义了4个增强处理,定义4个增强处理时分别指定了相同的切入点表达式,这种做法显然不太符合软件设计的原则:我们居然将那个切入点表达式重复了4次,如果有一天需要修改这个切入点表达式,那就要修改4个地方。如果重复了更多次呢?岁,我们就得修改更多次。
为了解决这个问题,AspectJ和Spring都允许定义切入点。所谓 定义切入点,其实质就是为一个切入点表达式起一个名称,从而允许在多个增强处理中重用该名称。
Spring AOP 只支持以Spring Bean的方法执行组作为连接点,所以可以把 切入点 看成所有能和切入表达式匹配的Bean方法。
切入点定义包括两个部分:
① 一个切入点表达式:用于指定该切入点和哪些方法进行匹配。
② 一个包含名字和任意参数的方法签名:作为该切入点的名称。
在@AspectJ风格的AOP中,切入点签名 采用一个普通的方法定义(方法体通常为空),且方法的返回值必须为void;切入点表达式需要使用@Pointcut注解来标注。
下面的代码片段定义了一个切入点,anyOldTransfer,这个切入点将匹配任何名为transfer的方法的执行:
//使用@Pointcut注解时指定切入点表达式
@Pointcut("execution(* transfer(..))")
//使用一个返回值为void,方法体为空的方法来命名切入点
private void anyOldTransfer(){}
切入点表达式,也就是组成@Pointcut注解的值,是正规的AspectJ5切入点表达式。如果想要更多了解AspectJ的切入点语法,参见AspectJ编程指南。
一旦采用上面的代码片段定义了名为anyOldTransfer的切入点之后,程序就可以多次重复使用该切入点了,甚至可以在其他切面类、其他包的切面类里使用该切入点,至于是否可以在其他切面类、其他包的切面类里访问该切入点,则取决于该方法签名前的访问控制符------例如,本示例中anyOldTransfer方法使用的是private修饰符,则意味着仅能在当前切面类中使用该切入点。
如果需要使用本切面类中的切入点,则可在使用@Pointcut时,指定value属性值为已有的切入点,如下所示:
@AfterReturning(pointcut="myPointcut()",returning="retVal")
public void writeLog(String msg,Object retVal){
...
}
可以看出,指定切入点时非常像调用Java方法的语法------只是该方法代表一个切入点,其实质是为该增强处理定义一个切入点表达式。
如果需要使用其他切面类中的切入点,则其他切面类中的切入点不能使用private修饰。如下程序的切面类中仅定义了一个切入点:
@Aspect
public class SystemArchitecture{
@Pointcut("execution(* org.crazyit.app.service.impl.Chin*.say*(..))")
public void myPointcut(){
}
}
下面的切面类中将直接使用上面定义的myPointcut切入点:
@Aspect
public class LogAspect {
@AfterReturning(pointcut="SystemArchitecture.myPointcut()&& args(msg)",returning="retVal")
public void writeLog(String msg,Object retVal){
System.out.println(msg);
System.out.println(retVal);
System.out.println("模拟记录日志...");
}
}