从ProceedingJoinPoint中检索参数值

时间:2014-12-26 16:34:20

标签: aop spring-aop spring-aspects

在我的请求中,我有一个参数名称“accessToken”,如何从ProceedingJoinPoint获取请求参数值?

public Object handleAccessToken(ProceedingJoinPoint joinPoint) throws Throwable { 
    final Signature signature = joinPoint.getStaticPart().getSignature();
    if (signature instanceof MethodSignature) {
        final MethodSignature ms = (MethodSignature) signature;
        String[] params = ms.getParameterNames();
        for (String param : params) {
            System.out.println(param);
            // here how do i get parameter value using param ?
        }
    }
}

通话方式:

public MyResponse saveUser(
    @RequestParam("accessToken") String accessToken,
    @RequestBody final UserDto userDto
) {
    // code 
}

我想在AOP中获取此访问令牌。

提前致谢。

2 个答案:

答案 0 :(得分:19)

好的,Shamseer,我只是有一点闲暇时间,所以我试图回答你的问题,而你没有回答我的评论中的所有问题。我这样做的方法是, 使用参数名称,但尝试将参数与注释@RequestParam("accessToken")匹配,即我将匹配注释类型和值,其魔术名称为“accessToken”而不是方法参数名称,由于在编译期间从类文件中删除调试信息或由于模糊处理而导致对不知道您方面的人进行简单重构,因此可能会更改该方法参数名称

这是一些自我一致的示例代码,它是针对AspectJ而不是Spring AOP进行测试的,但后者的语法无论如何都是前者语法的一个子集:

主要方法的示例类:

有三种方法,所有方法都在其中一个参数上有@RequestParam注释,但其中只有两个具有魔法值“accessToken”。无论参数类型如何,都应匹配它们(一个String和一个int),但@RequestParam("someParameter")不应匹配。严格地说,所有方法执行都是匹配的,但运行时反射可以消除不需要的方法。如果您的注释是在类或方法级别或参数类型上,我们可以直接在切入点中匹配它们而不进行反射,但在参数注释的情况下,这超出了AspectJ的当前(v1.8.4)功能,我们必须使用反射,不幸的是。

package de.scrum_master.app;

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

public class MyResponse {
    public MyResponse saveUser(
        @RequestParam("accessToken") String accessToken,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomething(
        @RequestParam("someParameter") String text,
        @RequestBody final UserDto userDto
    ) {
        return this;
    }

    public MyResponse doSomethingElse(
        @RequestParam("accessToken") int number
    ) {
        return this;
    }

    public static void main(String[] args) {
        MyResponse myResponse = new MyResponse();
        myResponse.doSomething("I am not a token", new UserDto());
        myResponse.saveUser("I am a token", new UserDto());
        myResponse.doSomethingElse(12345);
    }
}

使代码编译的虚拟助手类:

package de.scrum_master.app;

public class UserDto {}

<强>方面:

请注意,我的全能切入点execution(* *(..))仅供参考。你应该把它缩小到你真正想要的方法太匹配了。

package de.scrum_master.aspect;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.web.bind.annotation.RequestParam;

@Aspect
public class AccessTokenAspect {
    @Around("execution(* *(..))")
    public Object handleAccessToken(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        System.out.println(thisJoinPoint);
        Object[] args = thisJoinPoint.getArgs();
        MethodSignature methodSignature = (MethodSignature) thisJoinPoint.getStaticPart().getSignature();
        Method method = methodSignature.getMethod();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        assert args.length == parameterAnnotations.length;
        for (int argIndex = 0; argIndex < args.length; argIndex++) {
            for (Annotation annotation : parameterAnnotations[argIndex]) {
                if (!(annotation instanceof RequestParam))
                    continue;
                RequestParam requestParam = (RequestParam) annotation;
                if (! "accessToken".equals(requestParam.value()))
                    continue;
                System.out.println("  " + requestParam.value() + " = " + args[argIndex]);
            }
        }
        return thisJoinPoint.proceed();
    }
}

控制台输出:

execution(void de.scrum_master.app.MyResponse.main(String[]))
execution(MyResponse de.scrum_master.app.MyResponse.doSomething(String, UserDto))
execution(MyResponse de.scrum_master.app.MyResponse.saveUser(String, UserDto))
  accessToken = I am a token
execution(MyResponse de.scrum_master.app.MyResponse.doSomethingElse(int))
  accessToken = 12345

另请参阅this answer有关类似代码的相关但更简单的问题。

答案 1 :(得分:3)

要获得作为方法参数获得的参数,您可以尝试类似:

Object[] methodArguments = joinPoint.getArgs();