Spring AOP: получить доступ к именам аргументов - PullRequest
7 голосов
/ 17 февраля 2011

Я использую 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 " (полная отладка)и я бы предпочел не делать этого.

Есть ли какой-либо другой способ получить доступ к такого рода информации времени выполнения.

Спасибо L

Ответы [ 4 ]

6 голосов
/ 17 февраля 2011

К сожалению, вы не можете сделать это :-(. Это хорошо известное ограничение JVM / bytecode - имена аргументов не могут быть получены с помощью отражения, так как они не всегда хранятся в байт-коде (в отличие от метода /имена классов).

В качестве обходного пути несколько структур / спецификаций вводят пользовательские аннотации над аргументами, такими как WebParam (name свойство) или PathParam.

Пока все, что вы можете получить без аннотаций, это массив значений.

4 голосов
/ 17 февраля 2011

Проверьте реализации org.springframework.core.ParameterNameDiscoverer.

Аннотации типа @RequestParam, используемые пружиной, проверяют имя параметра, если не установлено значение value. Таким образом, @RequestParam String foo фактически выберет параметр запроса с именем "foo". Он использует механизм ParameterNameDiscoverer. Я просто не уверен, какая из реализаций используется, попробуйте каждую из них.

LocalVariableTableParameterNameDiscoverer читает .class и использует asm для проверки имен.

Итак, это возможно. Но обязательно кешируйте эту информацию (например, сохраняйте имя параметра на карте с ключом = класс + метод + индекс параметра).

Но, как отмечено в документации, вам нужна отладочная информация. Из документов @PathVariable:

Сопоставление имен параметров метода с именами переменных шаблона URI можно выполнить, только если ваш код скомпилирован с включенной отладкой. Если у вас не включена отладка, вы должны указать имя переменной шаблона URI в аннотации @PathVariable, чтобы связать разрешенное значение имени переменной с параметром метода

Итак, если вы действительно не хотите включать эту информацию, ответ Томаша Нуркевича объясняет обходной путь.

3 голосов
/ 10 сентября 2014

В Java 8 есть новый флаг компилятора, который позволяет хранить дополнительные метаданные с помощью байтового кода, и эти имена параметров могут быть извлечены с использованием объекта Parameter в отражении.См. JDK 8 spec .В более новых версиях hibernate org.springframework.core.ParameterNameDiscoverer использует эту функцию.Чтобы использовать его, скомпилируйте с помощью javac с этим флагом:

-parameters                Generate metadata for reflection on method parameters

Доступ к параметрам с использованием отражения Параметр класс.

1 голос
/ 17 марта 2017

Я не уверен, что это лучший способ, но я добавил аннотацию к своему методу:

Моя аннотация:

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

Это, вероятно, хак, но я не хотел компилировать больше опций для получения информации.В любом случае, это хорошо работает для меня.Единственным недостатком является то, что мне нужно держать имена в аннотации и метод в синхронизации.

...