Spring AOP - 带参数的注释

问题描述 投票:0回答:2

我在 spring boot 遇到了问题。我正在尝试为某些 RestController 提供额外的功能,并且我正在尝试通过一些自定义注释来实现它。这是一个例子。

我的注释:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyCustomAnnotation {
  String someArg();
}

我的方面:

@Aspect
@Component
public class MyAspect {
  @Around(
    value = "@annotation(MyCustomAnnotation)",
    argNames = "proceedingJoinPoint,someArg"
  )
  public Object addMyLogic(ProceedingJoinPoint proceedingJoinPoint, String someArg)
    throws Throwable
  {
    System.out.println(someArg);
    return proceedingJoinPoint.proceed();
  }
}

我的方法:

@MyCustomAnnotation(someArg = "something")
@GetMapping("/whatever/route")
public SomeCustomResponse endpointAction(@RequestParam Long someId) {
  SomeCustomResult result = someActionDoesNotMatter(someId);
  return new SomeCustomResponse(result);
}

主要基于文档(https://docs.spring.io/spring/docs/3.0.3.RELEASE/spring-framework-reference/html/aop.html - 7.2.4.6 建议参数)我很漂亮当然,它应该可以工作。

我在这里,因为它不...

让我发疯的是,即使是 Intellij,在尝试帮助 argNames(空字符串 -> 红色下划线 -> alt+enter -> 正确的 argNames 属性)时也给了我这个,并保持红色......

根据文档,甚至不需要 proceedingJoinPoint(没有它也无法工作):“如果第一个参数是 JoinPoint,ProceedingJoinPoint ...”

使用当前设置,它显示“未绑定切入点参数‘someArg’”

在这一点上,我还应该注意到,没有 args 它工作正常。

其实我有两个问题:

  1. 为什么这不起作用? (这很明显)

  2. 如果我想为某些控制器提供一些额外的功能,并且我想从外部对其进行参数化,那么它在 spring boot 中是正确的模式吗? (使用 python,使用装饰器很容易做到这一点——我不太确定,我没有被类似的语法误导)

一个例子(上面的例子很抽象):

我想创建一个@LogEndpointCall 注释,路由的开发者稍后可以将它放在他正在开发的端点上

...但是,如果他可以添加一个字符串(或者更可能是一个枚举)作为参数,那就太好了

@LogEndpointCall(EndpointCallLogEnum.NotVeryImportantCallWhoCares)

@LogEndpointCall(EndpointCallLogEnum.PrettySensitiveCallCheckItALot)

因此触发相同的逻辑,但使用不同的参数 -> 并保存到不同的目的地。

spring spring-boot spring-aop spring-annotations
2个回答
8
投票

您不能直接将注释属性绑定到通知参数。只需绑定注解本身并正常访问其参数即可:

@Around("@annotation(myCustomAnnotation)")
public Object addMyLogic(
  ProceedingJoinPoint thisJoinPoint,
  MyCustomAnnotation myCustomAnnotation
)
  throws Throwable
{
  System.out.println(thisJoinPoint + " -> " + myCustomAnnotation.someArg());
  return thisJoinPoint.proceed();
}

它会用 Spring AOP 打印这样的东西

execution(SomeCustomResponse de.scrum_master.app.Application.endpointAction(Long)) -> something

和 AspectJ 类似的东西(因为 AJ 也知道调用连接点,而不仅仅是执行)

call(SomeCustomResponse de.scrum_master.app.Application.endpointAction(Long)) -> something
execution(SomeCustomResponse de.scrum_master.app.Application.endpointAction(Long)) -> something

1
投票

如果你想让你的方法拦截考虑参数的方法,你必须在你的切入点表达式中明确提到它,让它在这里工作是你应该做的:

@Around(
value = "@annotation(MyCustomAnnotation) && args(someArg)",
argNames = "someArg")

注意我添加了&& args(someArg),你可以添加任意多的参数,在argNames中你可以省略proceedingJoinPoint

© www.soinside.com 2019 - 2024. All rights reserved.