Met behulp van Spring AOP methode-argumenten ophalen?

Ik gebruik Spring AOP en heb het onderstaande aspect:

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

Bovenstaand aspect onderschept de uitvoering van de addCustomermethode. addCustomermethode neemt string als invoer.
Maar ik moet de invoer loggen die is doorgegeven aan de addCustomer-methode binnen de logBefore-methode.
Is het mogelijk om dit te doen?


Antwoord 1, autoriteit 100%

Je hebt een paar opties:

Eerst kunt u de JoinPoint#getArgs()methode die een Object[]retourneert met alle argumenten van de geadviseerde methode. Afhankelijk van wat je ermee wilt doen, moet je misschien wat casten.

Ten tweede kun je de argspointcut-expressie als volgt gebruiken:

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

dan kan uw methode in plaats daarvan worden gedefinieerd als

public void logBefore(JoinPoint joinPoint, String yourString) 

Antwoord 2, autoriteit 23%

Ja, de waarde van elk argument kan worden gevonden met 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);
      ...
   }
}

Antwoord 3, autoriteit 13%

Als u alle argumenten moet loggen of als uw methode één argument heeft, kunt u eenvoudig getArgs gebruiken zoals beschreven in eerdere antwoorden.

Als u een specifieke arg moet loggen, kunt u deze annoteren en de waarde als volgt herstellen:

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

Gebruiksvoorbeelden:

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
}

Antwoord 4, autoriteit 10%

Er is ook een andere manier, als u één punt voor veel adviezen definieert, kan dit nuttig zijn:

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

Antwoord 5, autoriteit 5%

U kunt een van de volgende methoden gebruiken.

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

of

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

joinpoint.getArgs() retourneert objectarray. Aangezien de invoer een enkele tekenreeks is, wordt er maar één object geretourneerd.

In de tweede benadering moet de naam hetzelfde zijn in expressie en invoerparameter in de adviesmethode, dwz args(inputString)en public void logBefore2(JoinPoint joinPoint, String inputString)

Hier geeft addCustomer(String)de methode aan met één invoerparameter String.


Antwoord 6, autoriteit 3%

Als het een enkel String-argument is, doe dan:
joinPoint.getArgs()[0];


Antwoord 7, autoriteit 3%

u kunt de methode-parameter en de waarde ervan krijgen en indien geannoteerd met een annotatie met de volgende code:

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

Antwoord 8

als je @Aspect gebruikt, is een optie om deze methode toe te voegen aan je Aspect en stuur het JoinPoint en de naam van de parameter die je nodig hebt.

private Object getParameter(ProceedingJoinPoint joinPoint, String parameterName) {
    Object valueParameter = null;
    if (Objects.nonNull(joinPoint) && joinPoint.getSignature() instanceof MethodSignature
            && Objects.nonNull(parameterName) ) {
        MethodSignature method = (MethodSignature)joinPoint.getSignature();
        String[] parameters = method.getParameterNames();
        for (int t = 0; t< parameters.length; t++) {
            if( Objects.nonNull(parameters[t]) && parameters[t].equals(parameterName)) {
                Object[] obj = joinPoint.getArgs();
                valueParameter = obj[t];
            }
        }
    }
    return valueParameter;
}

en het oproepvoorbeeld:

Object parameterObject = getParameter(joinPoint, "nameClient");
if ( Objects.nonNull(parameterObject) ) {
    String parametro = String.valueOf(parameterObject);
}

Je hoeft alleen het type object te weten om te converteren

Other episodes