【问题标题】:Java AOP JoinPoint does not get parameter namesJava AOP JoinPoint 不获取参数名称
【发布时间】:2014-10-03 06:54:17
【问题描述】:


我正在使用 Java Spring Mvc 和 Spring AOP 从用户那里查找参数名称。
我有一个控制器,它从用户那里获取参数并调用服务。
我有一个在服务之前运行的方面。
方面应检查用户名和 apiKey 参数是否存在。
这是我的代码:

控制器:

@RequestMapping(method = RequestMethod.POST, produces=MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody String getDomainWithFoundIn(@RequestParam (value="domain") String domain, @RequestParam (value="user") String user, @RequestParam (value="apiKey") String apiKey) throws JsonGenerationException, JsonMappingException, IOException {
    return domainService.getDomainDataWithFoundIn(domain, user, apiKey);
}

域服务接口:

public interface IDomainService {
    public String getDomainDataWithFoundIn(String domainStr, String user, String apiKey);
}

域服务:

@Override
@ApiAuthentication
public String getDomainDataWithFoundIn(String domainStr, String user, String apiKey) {
//Do stuff here
}

还有我的 AOP 类:

@Component
@Aspect
public class AuthAspect {
@Before("@annotation(apiAuthentication)") 
public void printIt (JoinPoint joinPoint, ApiAuthentication apiAuthentication) throws NoAuthenticationParametersException, UserWasNotFoundException {
        final MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        final String[] parameterNames = signature.getParameterNames();
        **//parameterNames is null here.**
}

在这种情况下,我希望获得“域”、“用户”和“apiKey”参数名称。
知道我在这里缺少什么吗?
谢谢,
或者。

【问题讨论】:

  • 你已经有点说了你所期望的。现在告诉我们实际发生了什么。
  • 我在方面类上写的 - 我在 String[] parameterNames 上得到了 null 而不是参数名称。
  • 你是如何编译你的源代码的?
  • 我会先仔细检查一下。然后尝试调试并查看它去哪里找到参数名称。在 Spring 3.x 中,它会检查字节码,但可能在 Spring 4 中它使用新的 Method 方法来获取 Parameter 对象。
  • 这种情况发生在 AOP 与接口相交时,如果是类参数名称被填充。这可能是因为 spring 使用了不同的接口和类代理(CGLIB vs JDK)docs.spring.io/spring/docs/current/spring-framework-reference/…

标签: java spring spring-mvc spring-aop spring-aspects


【解决方案1】:

正如我在上面的评论中所说,根据代理类型,您可以或不可以访问参数名称。如果你的 bean 实现了接口,那么 Spring 会创建 JDK 代理,在这种代理中 MethodSignature.getParameterNames() 为空。如果您的 bean 没有实现接口,则创建 CGLIB 代理,其中填充 MethodSignature.getParameterNames()。

如果可以,您可以通过删除 bean 接口切换到 CGLIB 代理 bean,它应该可以工作。

我现在也遇到同样的问题,我无法删除接口。我为此想出了不同的解决方案。在界面上,我可以通过一些自定义注释来标记我的参数:

interface MyInterface {
  void myMetod(@ParamName("foo") Object foo, @ParamName("bar") Object bar);
}

现在在 AOP 代理中,我可以在以下位置获取此信息:

MethodSignature.getMethod().getParameterAnnotations()

【讨论】:

  • 感谢您的解释,现在我知道为什么总是为参数名称返回null...并且提供的解决方案是一个非常好的解决方法,但它似乎不符合 AOP 的原则哪些与逻辑无关的代码不应该添加。话虽如此,我没有比你更好的解决方案了。
【解决方案2】:

我只能在 Eclipse 中使用 Java 8 来完成这项工作。方法如下:

  • 右键单击项目 -> 属性 -> Java 构建路径 -> 库选项卡并确保添加 JDK 8 而不是现在的(在我的情况下,我有 JDK_1.7.0_51 并将其替换为 JDK_1 .8.0_05)。应用更改。
  • 转到 Java 编译器 -> 检查 Enable project specific settings -> 检查 Use default compliance settings 并将 Compiler compliance level 设置为 1.8。 Generated .class files compatibilitySource compatibility 也是如此。
  • Classfile Generation 部分确保选中Store method parameter names 选项(在我的测试中,我选中了Classfile Generation 下的所有选项)。在我的案例中,Store method parameter names 选项仅适用于 1.8 的合规级别。点击Ok
  • 清理并重新编译您的项目。
  • 我还在 Tomcat 7 上使用 JDK 8 运行我的项目。无需在调试模式下运行它。

在 STS 3.5.1 (Eclipse Kepler SR2 4.3.2) 中对此进行了测试。

【讨论】:

    【解决方案3】:

    最简单的方法是在你的配置文件中设置proxyTargetClass,即

    @EnableAspectJAutoProxy(proxyTargetClass = true)
    

    【讨论】:

    • 我不知道为什么这被否决了。它适用于春季文档To enable CGLIB, you need to set the attribute proxy-targetclass= true in aop:aspectj-autoproxy.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多