Получить значение параметра из ProceedingJoinPoint

В моем запросе у меня есть имя параметра «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.

Заранее спасибо.


person Shamseer PC    schedule 26.12.2014    source источник
comment
Пожалуйста, предоставьте больше информации, например. разрез точки аспекта и один или несколько образцов кода для перехвата, тип параметра и положение параметра (например, первый, второй, третий параметр при отсчете слева/справа от сигнатуры метода). Затем я предоставлю элегантный ответ с привязкой параметров вместо уродливого кода getArgs() или отражения.   -  person kriegaex    schedule 30.12.2014
comment
Спасибо за ответ, я пытался проверить accessToken. В моем приложении для отдыха я отправляю acceeesToken с телом запроса что-то вроде {accessToken:myValue}, мне нужно получить этот токен доступа из ProceedingJoinPoint.   -  person Shamseer PC    schedule 01.01.2015
comment
Хотелось бы код, а не описание в прозе. Я эксперт AspectJ, а не Spring.   -  person kriegaex    schedule 01.01.2015
comment
я только что отредактировал свой вопрос .. добавил исходный код метода вызова.   -  person Shamseer PC    schedule 05.01.2015
comment
Пожалуйста, также покажите точку на совете, а также имена классов/аспектов и пакеты, в которых они находятся. Поделитесь не просто фрагментами, пожалуйста, но дайте мне общую картину, в идеале SSCCE. Пожалуйста, также ответьте на мой предыдущий вопрос относительно позиций параметров, а также скажите, может ли быть более одного параметра с аннотацией токена доступа для каждого метода.   -  person kriegaex    schedule 05.01.2015
comment
Я также хотел бы знать, как безопасно идентифицировать параметр. Я бы предположил параметр аннотации, то есть accessToken в @RequestParameter, а не имя переменной, которое может легко измениться и не кажется очень надежным. Волшебные имена параметров — плохая идея.   -  person kriegaex    schedule 05.01.2015


Ответы (2)


Хорошо, Шамсир, у меня просто есть немного свободного времени, поэтому я пытаюсь ответить на твой вопрос, а ты не отвечаешь на все мои вопросы из моих комментариев. Я делаю это следующим образом: я не использую имена параметров, а пытаюсь сопоставить параметры с аннотацией @RequestParam("accessToken"), т.е. я буду сопоставлять тип аннотации и значение с магическим именем «accessToken», а не с именем параметра метода, которое может измениться из-за простого рефакторинга кем-то, кто не знает о вашем аспекте, из-за удаления отладочной информации из файла класса во время компиляции или из-за обфускации.

Вот некоторый самосогласованный пример кода, который был протестирован на AspectJ, а не на Spring AOP, но синтаксис последнего в любом случае является подмножеством синтаксиса первого:

Пример класса с основным методом:

Существует три метода, каждый из которых имеет аннотацию @RequestParam для одного из параметров, но только два из них имеют магическое значение «accessToken». Они должны совпадать независимо от типа параметра (один String и один int), но параметр с @RequestParam("someParameter") не должен совпадать. Строго говоря, все исполнения методов сопоставляются, но отражение во время выполнения устраняет нежелательные. Если ваши аннотации будут на уровне класса или метода или на типах параметров, мы могли бы сопоставить их непосредственно в pointcut без отражения, но в случае аннотаций параметров это выходит за рамки текущих возможностей 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

См. также этот ответ на связанный, но несколько более простой вопрос с аналогичным кодом.

person kriegaex    schedule 05.01.2015
comment
Возможно, вы хотите реорганизовать свой код и сделать токен доступа отдельным классом, а не простой строкой. Таким образом, вы можете работать безопасным способом, а также легко сопоставлять pointcuts с типом параметра, а не с именами переменных или значениями аннотаций. - person kriegaex; 06.01.2015
comment
@kriegaex Я хочу создать общий метод для приведенного выше кода, но столкнулся с проблемой, поскольку не могу передать AnnotationType в свой метод для строки if (!(annotation instanceof RequestParam {AnnotationType})) Как передать RequestParam в качестве параметра вашему коду - person KNDheeraj; 01.04.2019
comment
Комментарии к вопросам четырехлетней давности — не лучший инструмент, чтобы задавать и отвечать на новые вопросы, связанные или нет. Я предлагаю вам создать новый вопрос с помощью MCVE, со ссылкой на мой ответ здесь и объяснив, что именно вы хотите сделать и где и как это терпит неудачу. Спасибо. - person kriegaex; 01.04.2019
comment
Если вы хотите, чтобы argNames ссылались, stackoverflow.com/a/49155868/234110 делает что-то вроде этого String[] argNames = ((CodeSignature) joinPoint.getSignature()).getParameterNames(); - person Anand Rockzz; 06.07.2021
comment
Я знаю это, и я уже объяснил, что это плохая идея, потому что результатом будет (а) плохой дизайн, (б) хрупкость (ломание, если кто-то переименует параметр метода), (в) в этом случае ненужный, потому что мы может просто соответствовать аннотации параметра, (d) не работает, если скомпилирован без отладочной информации. - person kriegaex; 07.07.2021

Чтобы получить аргументы, которые вы получаете в качестве параметра метода, вы можете попробовать что-то вроде:

Object[] methodArguments = joinPoint.getArgs();
person SMA    schedule 26.12.2014
comment
Извините за мои вопросы, я не знаю, правильный мой вопрос или нет? использует ли метод getArgs() Reflection для получения параметров? - person fatemeakbari; 23.05.2021