AOP:在一个切入点中支持@annotation 和@within
AOP: Supporting @annotation and @within in one pointcut
我有一个注释可以放在 class 或方法上:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface TestAspectAnnotation {
String[] tags() default {};
}
我想要一个单一的建议方法来处理 class 级别和方法级别的用法:
@Around(value = "@annotation(annotation) || @within(annotation)", argNames = "pjp,annotation")
public Object testAdvice(ProceedingJoinPoint pjp,
TestAspectAnnotation annotation) throws Throwable {
String[] tags = annotation.tags();
Stopwatch stopwatch = Stopwatch.createStarted();
Object proceed = pjp.proceed();
stopwatch.stop();
long executionTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
sendMetrics(tags, executionTime);
return proceed;
}
当我用 TestAspectAnnotation(tags="foo")
注释 class 时,这工作正常。
但是,如果我注释一个方法,annotation
参数将是 null
。
有趣的是,如果我颠倒切入点指示符的顺序 ("@within(annotation) || @annotation(annotation)"
),那么我会遇到相反的问题:方法级注释可以正常工作,但 class 级注释会annotation
参数的结果是 null
。
有没有办法有一个切入点和建议来支持 class 级别和方法级别的注释?
Is there a way have a single pointcut and advice
我最近遇到了类似的问题,尝试了各种方法,但都无济于事。我最终将 "or" 切入点拆分为两个单独的切入点,并从两条建议中调用相同的方法。
我已经建立了一个小型演示项目来说明我已经建立的工作解决方案。希望对您有所帮助:
@Component
@Aspect
public class SomeAspect {
@Around(value = "@within(annotation)", argNames = "pjp,annotation")
public Object methodAdvice(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
return logTags(pjp, annotation);
}
@Around(value = "@annotation(annotation)", argNames = "pjp,annotation")
public Object classAdvice(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
return logTags(pjp, annotation);
}
private Object logTags(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
Stream.of(annotation.tags()).forEach(System.out::println);
return pjp.proceed();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SomeAnnotation {
String[] tags() default {};
}
@Service
@SomeAnnotation(tags = {"c", "d"})
public class SomeService {
@SomeAnnotation(tags = {"a", "b"})
public void test() {
}
}
@SpringBootApplication
public class Application implements ApplicationRunner {
@Autowired private SomeService someService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
someService.test();
}
}
我有一个注释可以放在 class 或方法上:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface TestAspectAnnotation {
String[] tags() default {};
}
我想要一个单一的建议方法来处理 class 级别和方法级别的用法:
@Around(value = "@annotation(annotation) || @within(annotation)", argNames = "pjp,annotation")
public Object testAdvice(ProceedingJoinPoint pjp,
TestAspectAnnotation annotation) throws Throwable {
String[] tags = annotation.tags();
Stopwatch stopwatch = Stopwatch.createStarted();
Object proceed = pjp.proceed();
stopwatch.stop();
long executionTime = stopwatch.elapsed(TimeUnit.MILLISECONDS);
sendMetrics(tags, executionTime);
return proceed;
}
当我用 TestAspectAnnotation(tags="foo")
注释 class 时,这工作正常。
但是,如果我注释一个方法,annotation
参数将是 null
。
有趣的是,如果我颠倒切入点指示符的顺序 ("@within(annotation) || @annotation(annotation)"
),那么我会遇到相反的问题:方法级注释可以正常工作,但 class 级注释会annotation
参数的结果是 null
。
有没有办法有一个切入点和建议来支持 class 级别和方法级别的注释?
Is there a way have a single pointcut and advice
我最近遇到了类似的问题,尝试了各种方法,但都无济于事。我最终将 "or" 切入点拆分为两个单独的切入点,并从两条建议中调用相同的方法。
我已经建立了一个小型演示项目来说明我已经建立的工作解决方案。希望对您有所帮助:
@Component
@Aspect
public class SomeAspect {
@Around(value = "@within(annotation)", argNames = "pjp,annotation")
public Object methodAdvice(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
return logTags(pjp, annotation);
}
@Around(value = "@annotation(annotation)", argNames = "pjp,annotation")
public Object classAdvice(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
return logTags(pjp, annotation);
}
private Object logTags(ProceedingJoinPoint pjp, SomeAnnotation annotation) throws Throwable {
Stream.of(annotation.tags()).forEach(System.out::println);
return pjp.proceed();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface SomeAnnotation {
String[] tags() default {};
}
@Service
@SomeAnnotation(tags = {"c", "d"})
public class SomeService {
@SomeAnnotation(tags = {"a", "b"})
public void test() {
}
}
@SpringBootApplication
public class Application implements ApplicationRunner {
@Autowired private SomeService someService;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(ApplicationArguments args) throws Exception {
someService.test();
}
}