【问题标题】:Spring AOP: get access to argument namesSpring AOP:访问参数名称
【发布时间】:2011-02-17 15:03:18
【问题描述】:

我正在使用 Spring 3.x、Java 6。

我有一个带有以下连接点的@Around 方面:

@Around("execution(public * my.service.*.*Connector.*(..))")

所以,我基本上有兴趣拦截对类名以“连接器”结尾的类的公共方法的所有调用。到目前为止一切顺利。

现在,就我而言,我想访问方法的实际参数名称:

public doStuff(String myarg, Long anotherArg)

myarganotherArg

我明白使用:

CodeSignature signature = (CodeSignature)jointPoint.getSignature();
return signature.getParameterNames();

实际上会起作用,但前提是我使用“-g”标志编译代码(完全调试)并且我宁愿不这样做。

有没有其他方法可以访问这种运行时信息。

谢谢 升

【问题讨论】:

    标签: java spring spring-aop


    【解决方案1】:

    不幸的是你不能这样做:-(。这是 JVM/字节码的一个众所周知的限制 - 不能使用反射获得参数名称,因为它们并不总是存储在字节码中(与方法 /类名)。

    作为一种解决方法,一些框架/规范在 WebParamname 属性)或 PathParam 等参数上引入了自定义注释。

    暂时没有注释你能得到的只是一个值数组。

    【讨论】:

    • 这里我不确定,但我认为确实无法使用反射获得它们,但它们未存储在字节码中不一定是真的。如问题中所述,它们在使用(至少)javac -g:vars ... 编译时存储,因此它们可以显示在调试器中。 (如果我错了,请纠正我)
    • 感谢您的澄清,我稍微修改了原始答案。
    • 你能详细解释一下“pathParam”和“WebParam”吗?
    • 可能在 2011 年这个答案是正确的,但是由于引入了 -parameters 编译器开关(@junkgui 也提到了),您可以 a)将参数信息编译到您的类文件中 b)获取从当前的 AspectJ 版本访问该信息。但问题是关于 Java 6,所以对于那个版本,这个答案仍然是正确的。
    【解决方案2】:

    检查org.springframework.core.ParameterNameDiscoverer 的实现。

    如果没有设置value,spring 使用的@RequestParam 等注解检查参数名称。所以@RequestParam String foo 实际上会获取名为“foo”的请求参数。它使用ParameterNameDiscoverer 机制。我只是不确定使用了哪些实现,请尝试每一个。

    LocalVariableTableParameterNameDiscoverer 读取 .class 并使用 asm 检查名称。

    所以,这是可能的。但请确保缓存此信息(例如 - 将参数名称存储在 map 中,key = class+method+parameter index)。

    但是,正如文档中所述,您需要调试信息。来自@PathVariable的文档:

    方法参数名称与 URI 模板变量名称的匹配只有在您的代码在启用调试的情况下编译时才能完成。如果您没有启用调试,则必须在@PathVariable 注解中指定URI Template 变量名的名称,以便将变量名的解析值绑定到方法参数

    因此,如果您真的不想包含该信息,Tomasz Nurkiewicz 的回答解释了解决方法。

    【讨论】:

    • 感谢 Bozhidar,LocalVariableTableParameterNameDiscoverer 的 Javadoc 说:如果类文件是在没有调试信息的情况下编译的,则返回 * null
    • @Luciano Fiandesio 是的,是的。我会更新以包含更多信息
    【解决方案3】:

    在 Java 8 中有一个新的编译器标志,它允许使用字节码存储额外的元数据,并且可以使用反射中的 Parameter 对象提取这些参数名称。见JDK 8 spec。在较新版本的休眠 org.springframework.core.ParameterNameDiscoverer 中使用此功能。要使用它,请使用带有此标志的 javac 进行编译:

    -parameters                Generate metadata for reflection on method parameters
    

    使用反射的Parameter 类访问参数。

    【讨论】:

      【解决方案4】:

      我不确定这是否是最好的方法,但我在我的方法上添加了注释:

      我的注释:

      @Retention (RetentionPolicy.RUNTIME)
      @Target (ElementType.METHOD)
      public @interface ReadApi
      {
          String[] paramNames() default "";
      }
      
      @ReadApi (paramNames={"name","id","phone"})
      public Address findCustomerInfo(String name, String id, String phone)
      { ..... }
      

      在方面:

      @Around("aspect param && @annotation(readApi)")
      public Object logParams(ProceedingJoinPoint pjp,
              ReadApi readApi) 
      {
          //use pjp.getArgs() and readApi.paramNames();
      }
      

      这可能是一个 hack,但我不想编译更多选项来获取信息。无论如何,它对我来说效果很好。唯一的缺点是我需要保持注释和方法中的名称同步。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-03
        • 1970-01-01
        • 1970-01-01
        • 2021-12-17
        • 1970-01-01
        • 2020-09-29
        • 1970-01-01
        相关资源
        最近更新 更多