87 votes

Obtenir les arguments d'une méthode en utilisant Spring AOP ?

J'utilise Spring AOP et j'ai l'aspect suivant :

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

}

Intercepts d'aspect supérieur addCustomer l'exécution de la méthode. addCustomer prend une chaîne de caractères en entrée. Mais j'ai besoin d'enregistrer l'entrée passée à addCustomer méthode à l'intérieur logBefore méthode.
Est-il possible de le faire ?

116voto

Sotirios Delimanolis Points 77933

Vous avez quelques options :

Tout d'abord, vous pouvez utiliser le JoinPoint#getArgs() qui renvoie un Object[] contenant tous les arguments de la méthode conseillée. Il se peut que vous deviez effectuer un casting en fonction de ce que vous voulez faire avec eux.

Deuxièmement, vous pouvez utiliser le args comme ceci :

// 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,..)")

alors votre méthode peut être définie comme suit

public void logBefore(JoinPoint joinPoint, String yourString)

30voto

Reimeus Points 93429

Oui, la valeur de n'importe quel argument peut être trouvée en utilisant 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);
      ...
   }
}

17voto

andolsi zied Points 1847

Si vous devez enregistrer tous les arguments ou si votre méthode n'a qu'un seul argument, vous pouvez simplement utiliser getArgs comme décrit dans les réponses précédentes.

Si vous devez enregistrer un arg spécifique, vous pouvez l'annoter et ensuite récupérer sa valeur comme ceci :

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

Exemples d'utilisation :

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
}

12voto

Iwo Kucharski Points 2573

Il y a aussi une autre façon de faire, si vous définissez un raccourci ponctuel pour plusieurs conseils, cela peut être utile :

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

6voto

sunj Points 101

Vous pouvez utiliser l'une des méthodes suivantes.

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

ou

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

joinpoint.getArgs() renvoie un tableau d'objets. Comme l'entrée est une seule chaîne de caractères, un seul objet est renvoyé.

Dans la deuxième approche, le nom doit être le même dans l'expression et le paramètre d'entrée dans la méthode de conseil, c'est-à-dire args(inputString) y public void logBefore2(JoinPoint joinPoint, String inputString)

Ici, addCustomer(String) indique la méthode avec un paramètre d'entrée de type String.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X