86

私はSpringAOPを使用しており、以下の側面があります。

@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
そうすることは可能ですか?

4

8 に答える 8

116

いくつかのオプションがあります。

まず、アドバイスされたメソッドのすべての引数を含む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,..)")

その場合、代わりにメソッドを次のように定義できます。

public void logBefore(JoinPoint joinPoint, String yourString) 
于 2013-03-27T14:01:00.590 に答える
28

はい、引数の値は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);
      ...
   }
}
于 2013-03-27T13:59:51.500 に答える
15

すべての引数をログに記録する必要がある場合、またはメソッドに1つの引数がある場合は、前の回答で説明したように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
}
于 2017-11-02T15:28:57.557 に答える
12

多くのアドバイスに対して1つのポイントカットを定義する場合、それが役立つ可能性がある別の方法もあります。

@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());
}
于 2016-04-12T13:15:04.087 に答える
6

次のいずれかの方法を使用できます。

@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()はオブジェクト配列を返します。入力は単一の文字列であるため、1つのオブジェクトのみが返されます。

2番目のアプローチでは、名前はアドバイスメソッドの式と入力パラメーターで同じである必要がありますargs(inputString)public void logBefore2(JoinPoint joinPoint, String inputString)

ここでaddCustomer(String)は、1つの文字列入力パラメータを持つメソッドを示します。

于 2015-11-07T06:46:06.387 に答える
3

単一の文字列引数の場合は、次のようにします。 joinPoint.getArgs()[0];

于 2013-03-27T14:00:14.127 に答える
3

メソッドパラメータとその値を取得できます。注釈が付けられている場合は、次のコードを使用します。

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;
    }
于 2017-03-05T06:15:51.653 に答える
2

@Aspectを使用している場合は、オプションとしてこのメ​​ソッドをアスペクト内に追加し、JoinPointと必要なパラメーターの名前を送信します。

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

と呼び出しの例:

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

変換するオブジェクトのタイプを知る必要があるだけです

于 2020-05-11T22:13:42.100 に答える