针对同一个切入点,如果有多个通知方法将切入时,通常我们需要标注多个注解,每个注解需要使用切入点表达式,告诉spring,当前通知方法在何时执行。当一个切入点需要更改时,就需要同时更改多个。为了避免这种麻烦,提高切入点表达式的可重用性,以此衍生出的@Pointcut,可以用于标志一个切入点。
示例:
如前文中的切面类StudentServiceLogger
,针对StudentServiceImpl
类的所有方法都切入了四个通知,如果某天,我想改成只对其中一个方法切入时,就需要来修改这四个注解的切入点表达式。
@Aspect
@Component
public class StudentServiceLogger {
@Before("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )")
public void doBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法执行前...");
System.out.println("参数为:"+ Arrays.asList(args));
}
@After("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )")
public void doAfter(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法执行后...");
}
@AfterReturning(value = "execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )" , returning = "returning")
public void doReturn(JoinPoint joinPoint,Object returning){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法返回,返回值为:"+returning);
}
@AfterThrowing(value = "execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )",throwing = "ex")
public void doThrow(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法异常,异常信息为:"+ex.getMessage());
}
}
使用@Pointcut的示例
上面的示例,完全等价于下面这个切面类。
@Aspect
@Component
public class StudentServiceLogger {
@Pointcut("execution(* com.wuwl.service.impl.StudentServiceImpl.*(..) )")
public void basePointCut(){}
@Before("basePointCut()")
public void doBefore(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法执行前...");
System.out.println("参数为:"+ Arrays.asList(args));
}
@After("basePointCut()")
public void doAfter(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法执行后...");
}
@AfterReturning(value = "basePointCut()" , returning = "returning")
public void doReturn(JoinPoint joinPoint,Object returning){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法返回,返回值为:"+returning);
}
@AfterThrowing(value = "basePointCut()",throwing = "ex")
public void doThrow(JoinPoint joinPoint,Exception ex){
String methodName = joinPoint.getSignature().getName();
System.out.println(methodName+"方法异常,异常信息为:"+ex.getMessage());
}
}
我们声明了一个basePointCut()
空方法,并且返回值需要为void,为该方法标注上@Pointcut
注解,键入之前我们那四个通知方法的公用切入点表达式。然后,将后续的所有使用到之前那个切入表达式的地方,替换成basePointCut()
这个方法名,以此指向同一个的切入点表达式。后续的所有变动,我都可以只更改basePointCut()
方法上的切入表达式即可。