2013-03-27 11 views
35

Ich bin mit Spring AOP und haben unter Aspekt: ​​Methodenargumente mit Spring AOP abrufen?

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

} 

Above Aspekt fängt addCustomer Ausführung der Methode. addCustomer Methode nimmt String als Eingabe. Aber ich muss Eingang protokollieren, der an addCustomer Methode innerhalb logBefore Methode übergeben wird.
Ist es möglich, dies zu tun?

+0

Was die Methodensignatur von 'AddCustomer ist (..) '? –

Antwort

46

Sie haben ein paar Optionen:

Erstens Sie können die Methode JoinPoint#getArgs() verwenden, die eine Object[] zurückgibt, die alle Argumente der empfohlenen Methode enthält. Je nachdem, was Sie mit ihnen machen möchten, müssen Sie möglicherweise ein Casting durchführen.

Zweitens können Sie die args pointcut Ausdruck wie so verwenden:

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

dann stattdessen Ihre Methode kann als

public void logBefore(JoinPoint joinPoint, String yourString) 
+2

Wenn ich mich nicht irre, gibt es einen Unterschied im Verhalten zwischen den 2 Optionen. Der zweite wird nur ausgelöst, wenn das Argument existiert, während der erste ausgelöst wird, auch wenn das Argument nicht existiert. –

+0

@SamuelEUSTACHI Es wurde kein Punktausdruck für das erste Beispiel angegeben. Wenn wir eine Ausführung von 'addCustomer (..)' annehmen, ist das sicher. Kann keine Argumente oder viele sein. –

15

Ja, kann der Wert jedes Argument 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); 
     ... 
    } 
} 
1

gefunden werden, wenn es Argument ein einzelnes String ist, tun: joinPoint.getArgs()[0];

2

Sie können eine der folgenden Methoden definiert werden.

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

oder

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

joinpoint.getArgs() gibt Objektarray. Da die Eingabe eine einzelne Zeichenfolge ist, wird nur ein Objekt zurückgegeben.

Im zweiten Ansatz sollte der Name in Ausdruck und Eingabeparameter in der Beratung Methode d.h. args(inputString) und public void logBefore2(JoinPoint joinPoint, String inputString)

hier gleich sein, zeigt addCustomer(String) das Verfahren mit einem String-Parameter.

2

Es gibt auch eine andere Art und Weise, wenn Sie eine pointcut für viele Ratschläge definieren kann es hilfreich sein:

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

Sie Methodenparameter und seinen Wert erhalten und wenn mit einer Anmerkung mit folgendem Code kommentiert:

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; 
    } 
1

Wenn Sie alle args oder Ihre Ihre Methode ein Argument loggt haben, können Sie Simpl Verwenden Sie getArgs wie in vorherigen Antworten beschrieben.

Wenn Sie einen bestimmten arg loggt haben, können Sie es annoted und dann seinen Wert wie folgt wieder her:

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

Beispiele:

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 
}