Spring AOP:访问参数名称

时间:2011-02-17 15:03:19

标签: java spring spring-aop

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

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

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

所以,我基本上对拦截所有对类的公共方法的调用感兴趣,类名以“Connector”结尾。到目前为止一切都很好。

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

public doStuff(String myarg, Long anotherArg)

myarg anotherArg

我明白使用:

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

实际上可以正常工作,但只有当我使用“ -g ”标志(完全调试)编译代码时,我宁愿不这样做。

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

由于 →

4 个答案:

答案 0 :(得分:6)

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

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

目前,没有注释的所有内容都是一系列值。

答案 1 :(得分:4)

检查org.springframework.core.ParameterNameDiscoverer的实施情况。

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

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

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

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

  

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

所以,如果你真的不想包含这些信息,Tomasz Nurkiewicz的答案解释了解决方法。

答案 2 :(得分:3)

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

-parameters                Generate metadata for reflection on method parameters

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

答案 3 :(得分:1)

我不确定它是否是最佳方式,但我在方法上添加了注释:

我的注释:

@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();
}

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