programing

Spring AOP를 사용하여 메소드 인수를 얻습니까?

kingscode 2021. 1. 18. 08:11
반응형

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메서드에 전달 된 입력을 기록해야합니다 .
그렇게 할 수 있습니까?


몇 가지 옵션이 있습니다.

먼저, 권고 된 메서드의 모든 인수를 포함 JoinPoint#getArgs()하는를 반환하는 메서드를 사용할 수 있습니다 Object[]. 당신이 그들과 함께하고 싶은 것에 따라 약간의 캐스팅을해야 할 수도 있습니다.

둘째, 다음 args과 같이 pointcut 표현식을 사용할 수 있습니다 .

// 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) 

예, 모든 인수의 값은 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);
      ...
   }
}

모든 인수를 기록해야하거나 메서드에 하나의 인수가있는 경우 이전 답변에서 설명한대로 간단히 getArgs를 사용할 수 있습니다.

특정 인수를 기록해야하는 경우 주석을 달고 다음과 같이 값을 복구 할 수 있습니다.

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

많은 조언에 대해 하나의 포인트 컷을 정의하면 도움이 될 수있는 또 다른 방법이 있습니다.

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

다음 방법 중 하나를 사용할 수 있습니다.

@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)하나의 문자열 입력 매개 변수가있는 메소드를 나타냅니다.


단일 문자열 인수 인 경우 다음을 수행하십시오. joinPoint.getArgs()[0];


메소드 매개 변수와 그 값을 얻을 수 있으며 다음 코드로 주석이 추가 된 경우 :

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

ReferenceURL : https://stackoverflow.com/questions/15660535/get-method-arguments-using-spring-aop

반응형