我正在使用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 ”标志(完全调试)编译代码时,我宁愿不这样做。
是否有其他方法可以访问这种运行时信息。
由于 →
答案 0 :(得分:6)
不幸的是你不能这样做:-(。这是一个众所周知的JVM /字节码限制 - 使用反射无法获得参数名称,因为它们并不总是存储在字节码中(与方法/相反)班级名称)。
作为一种解决方法,一些框架/规范会在WebParam
(name
属性)或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();
}
这可能是一个黑客,但我不想编译更多选项来获取信息。无论如何,它对我来说效果很好。唯一的缺点是我需要保持注释和方法中的名称同步。