Получить аргументы метода с помощью spring aop?

Я использую spring AOP и имею следующий аспект:

@Aspect
public class LoggingAspect {

    @Before("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")
    public void logBefore(JoinPoint joinPoint) {

        System.out.println("logBefore() is running!");
        System.out.println("hijacked : " + joinPoint.getSignature().getName());
        System.out.println("******");
    }

}

Вышеуказанный аспект перехватывает выполнение метода addCustomer. addCustomer метод принимает строку как вход. Но мне нужно записать вход, переданный методу addCustomer внутри метода logBefore.
Можно ли это сделать?

Ответ 1

У вас есть несколько вариантов:

Сначала вы можете использовать метод JoinPoint#getArgs(), который возвращает Object[], содержащий все аргументы рекомендуемого метода. Возможно, вам придется выполнять кастинг в зависимости от того, что вы хотите с ними делать.

Во-вторых, вы можете использовать выражение pointcut args следующим образом:

// use '..' in the args expression if you have zero or more parameters at that point
@Before("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..)) && args(yourString,..)")

тогда ваш метод может быть определен как

public void logBefore(JoinPoint joinPoint, String yourString) 

Ответ 2

Да, значение любого аргумента можно найти с помощью getArgs

@Before("execution(* com.mkyong.customer.bo.CustomerBo.addCustomer(..))")
public void logBefore(JoinPoint joinPoint) {

   Object[] signatureArgs = thisJoinPoint.getArgs();
   for (Object signatureArg: signatureArgs) {
      System.out.println("Arg: " + signatureArg);
      ...
   }
}

Ответ 3

Можно использовать один из следующих способов.

@Before("execution(* ong.customer.bo.CustomerBo.addCustomer(String))")
public void logBefore1(JoinPoint joinPoint) {
    System.out.println(joinPoint.getArgs()[0]);
 }

или

@Before("execution(* ong.customer.bo.CustomerBo.addCustomer(String)), && args(inputString)")
public void logBefore2(JoinPoint joinPoint, String inputString) {
    System.out.println(inputString);
 }

joinpoint.getArgs() возвращает массив объектов. Так как ввод является одной строкой, возвращается только один объект.

Во втором подходе имя должно быть одинаковым в выражении и параметре ввода в методе консультаций, т.е. args(inputString) и public void logBefore2(JoinPoint joinPoint, String inputString)

Здесь addCustomer(String) указывает метод с одним входным параметром String.

Ответ 4

Есть и другой способ, если вы определите один pointcut для многих советов, это может быть полезно:

@Pointcut("execution(@com.stackoverflow.MyAnnotation * *(..))")
protected void myPointcut() {
}

@AfterThrowing(pointcut = "myPointcut() && args(someId,..)", throwing = "e")
public void afterThrowingException(JoinPoint joinPoint, Exception e, Integer someId) {
    System.out.println(someId.toString());
}

@AfterReturning(pointcut = "myPointcut() && args(someId,..)")
public void afterSuccessfulReturn(JoinPoint joinPoint, Integer someId) {
    System.out.println(someId.toString());
}

Ответ 5

Если это единственный аргумент String, выполните следующие действия: joinPoint.getArgs()[0];

Ответ 6

вы можете получить параметр метода и его значение и аннотировать аннотацию следующим кодом:

Map<String, Object> annotatedParameterValue = getAnnotatedParameterValue(MethodSignature.class.cast(jp.getSignature()).getMethod(), jp.getArgs()); ....

private Map<String, Object> getAnnotatedParameterValue(Method method, Object[] args) {
        Map<String, Object> annotatedParameters = new HashMap<>();
        Annotation[][] parameterAnnotations = method.getParameterAnnotations();
        Parameter[] parameters = method.getParameters();

        int i = 0;
        for (Annotation[] annotations : parameterAnnotations) {
            Object arg = args[i];
            String name = parameters[i++].getDeclaringExecutable().getName();
            for (Annotation annotation : annotations) {
                if (annotation instanceof AuditExpose) {
                    annotatedParameters.put(name, arg);
                }
            }
        }
        return annotatedParameters;
    }

Ответ 7

Если вам нужно зарегистрировать все аргументы или ваш метод имеет один аргумент, вы можете просто использовать getArgs, как описано в предыдущих ответах.

Если вам нужно зарегистрировать определенный аргумент arg, вы можете записать его, а затем восстановить его значение следующим образом:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface Data {
 String methodName() default "";
}

@Aspect
public class YourAspect {

 @Around("...")
 public Object around(ProceedingJoinPoint point) throws Throwable {
  Method method = MethodSignature.class.cast(point.getSignature()).getMethod();
  Object[] args = point.getArgs();
  StringBuilder data = new StringBuilder();
    Annotation[][] parameterAnnotations = method.getParameterAnnotations();
    for (int argIndex = 0; argIndex < args.length; argIndex++) {
        for (Annotation paramAnnotation : parameterAnnotations[argIndex]) {
            if (!(paramAnnotation instanceof Data)) {
                continue;
            }
            Data dataAnnotation = (Data) paramAnnotation;
            if (dataAnnotation.methodName().length() > 0) {
                Object obj = args[argIndex];
                Method dataMethod = obj.getClass().getMethod(dataAnnotation.methodName());
                data.append(dataMethod.invoke(obj));
                continue;
            }
            data.append(args[argIndex]);
        }
    }
 }
}

Примеры использования:

public void doSomething(String someValue, @Data String someData, String otherValue) {
    // Apsect will log value of someData param
}

public void doSomething(String someValue, @Data(methodName = "id") SomeObject someData, String otherValue) {
    // Apsect will log returned value of someData.id() method
}