在 @Pointcut 注解中,可以使用变量名来代表一个注解类型。具体使用方式如下:
- 定义一个注解类型,如下所示:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Log {
String value();
}
上面的代码定义了一个名为 Log 的注解,该注解有一个 value 属性。
- 在切面类中使用 @Pointcut 注解,并使用变量名代表注解类型,如下所示:
@Pointcut("@annotation(log)")
public void logPointcut(Log log) {}
上面的代码中,log 是一个变量名,代表 Log 注解类型。
- 在切面类的通知方法中,可以使用该变量名来获取注解的属性值,如下所示:
@Before("logPointcut(log)")
public void beforeLog(JoinPoint joinPoint, Log log) {
String value = log.value();
// ...
}
上面的代码中,beforeLog 方法中的 Log log 参数就是从切点方法上获取到的注解实例,可以使用 log.value() 来获取注解的 value 属性值。
使用变量名来代表注解类型,可以让切面类更加灵活,可以匹配多个不同的注解类型,而不需要每个注解类型都定义一个 Pointcut。
- 可以使用内链接切点表达式,进行更简化的写法
@AfterReturning(value = "@annotation(logAnnotation)", returning = "result")
public void afterLog(JoinPoint joinPoint, Log logAnnotation, Object result) {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
String logMsg = logAnnotation.value();
String methodName = method.getName();
Object[] args = joinPoint.getArgs();
// 记录日志
// ...
}
扩展:内联切点表达式的语法主要包括切点指示符和切点表达式,具体如下:
- 切点指示符:切点指示符用于指示切点的类型和作用范围,通常使用注解来定义。常用的切点指示符包括:
- @Before:在目标方法执行之前执行切面逻辑;
- @After:在目标方法执行之后执行切面逻辑;
- @Around:在目标方法执行前后都可以执行切面逻辑;
- @AfterReturning:在目标方法返回结果后执行切面逻辑;
- @AfterThrowing:在目标方法抛出异常后执行切面逻辑。
- 切点表达式:切点表达式用于定义切点的作用范围和匹配规则,通常使用AspectJ切点表达式语言来定义。常用的切点表达式包括:
- execution:匹配方法执行的切点,可以使用通配符匹配方法名和参数列表;
- within:匹配指定类型内的所有方法的切点;
- this:匹配当前对象实例的切点;
- target:匹配目标对象实例的切点;
- args:匹配方法参数的切点;
- @annotation:匹配指定注解的切点。
切点表达式的语法规则与正则表达式类似,可以使用通配符和操作符来匹配不同的规则,例如:
- *:匹配任意字符或任意数量的字符;
- …:匹配任意数量的参数;
- &&:逻辑与操作符;
- ||:逻辑或操作符;
- !:逻辑非操作符。
切点表达式的具体语法和用法可以参考AspectJ官方文档。需要注意的是,切点表达式的语法和规则较为复杂,需要根据具体的需求和场景来选择合适的表达式。
@annotation是AspectJ切点表达式中的一个限定符,用于匹配标注了指定注解的方法或类。其语法如下:
@annotation(注解类型)
其中,注解类型是要匹配的注解的类类型,可以是Java内置的注解类型,也可以是自定义的注解类型。
使用@annotation限定符可以方便地对标注了指定注解的方法或类进行切面处理,例如:
@Around("@annotation(com.example.annotation.Loggable)") public Object logMethod(ProceedingJoinPoint joinPoint) throws Throwable { // 切面逻辑代码 ... }
上面的代码中,@Around注解指示了切面类型和切点表达式,即在执行标注了@Loggable注解的方法时执行该切面逻辑代码。
通过@annotation限定符,我们可以将切点表达式限定在标注了特定注解的方法或类上,使得切面逻辑只对这些方法或类生效,从而更加精确地控制切面的作用范围。同时,也可以提高代码的可读性和可维护性,因为注解通常用来描述方法或类的作用和用途,可以更直观地表达切点的含义和作用范围。
另外,@annotation限定符可以传入一个变量名作为参数,用于在切面中获取被匹配方法或类上的注解对象。具体来说,@annotation限定符的语法如下:
@annotation(注解类型变量名)
其中,注解类型变量名是一个字符串,用于指定一个变量名,该变量会在切面代码中被声明并赋值为被匹配方法或类上的注解对象。
例如,假设我们有一个自定义注解@Loggable,用于标记需要记录日志的方法,其定义如下:
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Loggable { String value() default ""; }
我们可以在切面中使用@annotation限定符,将标注了@Loggable注解的方法匹配出来,同时将被匹配方法上的注解对象赋值给一个变量,例如:
@Around("@annotation(loggable)") public Object logMethod(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable { String methodName = joinPoint.getSignature().getName(); String logMessage = "Method " + methodName + " executed with arguments: " + Arrays.toString(joinPoint.getArgs()); if (!loggable.value().isEmpty()) { logMessage += ", log message: " + loggable.value(); } log.info(logMessage); return joinPoint.proceed(); }
上面的代码中,@Around注解指示了切面类型和切点表达式,即在执行标注了@Loggable注解的方法时执行该切面逻辑代码。同时,将被匹配方法上的@Loggable注解对象赋值给了一个名为loggable的变量,可以在切面逻辑中使用该变量来访问注解对象的属性值。
通过@annotation限定符传入变量名,我们可以在切面中获取被匹配方法或类上的注解对象,并根据注解对象的属性值来动态控制切面逻辑的行为,从而实现更加灵活和智能的切面处理。