使用Spring AOP获取方法参数?

use*_*403 55 java spring

我正在使用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("******");
    }

}
Run Code Online (Sandbox Code Playgroud)

以上方面截获addCustomer方法执行.addCustomermethod将string作为输入.但我需要记录传入addCustomer方法内部的logBefore方法输入.
有可能这样做吗?

Sot*_*lis 81

你有几个选择:

首先,您可以使用JoinPoint#getArgs()返回Object[]包含建议方法的所有参数的方法.您可能需要进行一些投射,具体取决于您要对它们执行的操作.

其次,您可以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,..)")
Run Code Online (Sandbox Code Playgroud)

那么你的方法可以定义为

public void logBefore(JoinPoint joinPoint, String yourString) 
Run Code Online (Sandbox Code Playgroud)

  • 如果我没有弄错的话,两个选项之间的行为有所不同.第二个只会在arg存在时触发,而第一个将触发,即使参数不存在. (5认同)

Rei*_*eus 18

是的,可以使用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);
      ...
   }
}
Run Code Online (Sandbox Code Playgroud)


and*_*ied 7

如果必须记录所有args或方法具有一个参数,则可以像前面的答案中所述简单地使用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]);
        }
    }
 }
}
Run Code Online (Sandbox Code Playgroud)

使用示例:

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
}
Run Code Online (Sandbox Code Playgroud)

  • `"..." ` 表示完成您的模式。 (2认同)

小智 6

您可以使用以下任一方法。

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

或者

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

joinpoint.getArgs() 返回对象数组。由于输入是单个字符串,因此只返回一个对象。

在第二种方法中,该名称应在表达和输入参数相同的通知方法,即args(inputString)public void logBefore2(JoinPoint joinPoint, String inputString)

此处,addCustomer(String)表示具有一个 String 输入参数的方法。


Iwo*_*ski 6

如果为许多建议定义一个切入点,还有另一种方法,它可能会有所帮助:

@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());
}
Run Code Online (Sandbox Code Playgroud)