【问题标题】:Spring AOP - ProceedingJoinpoint - MethodSignature DowncastSpring AOP - ProceedingJoinpoint - MethodSignature Downcast
【发布时间】:2017-07-18 20:29:22
【问题描述】:

有没有办法从 ProceedingJoinPoint 获取 MethodSignature 而无需向下转换?

    private String toEventString(ProceedingJoinPoint pjp) {
    MethodSignature methodSignature = ((MethodSignature)pjp.getSignature());

    StringBuilder sb = new StringBuilder();

    String[] paramNames = methodSignature.getParameterNames();
    Class[] paramTypes = methodSignature.getParameterTypes();

    sb.append(methodSignature.getName()).append('(');

    for(int i = 0; i < paramNames.length; i++) {
        sb
            .append(paramTypes[i].getSimpleName())
            .append(" ")
            .append(paramNames[i]);
        if(i < paramNames.length - 1) {
            sb.append(", ");
        }
    }

    return sb.append(" )").toString();

}

【问题讨论】:

  • 旁注:StringJoiner 可以简化您的代码。
  • 另一个旁注:我已经使用 AspectJ 很长时间了。如果您可以只记录thisJoinPointthisJoinPoint.getSignature(),我从来没有真正理解记录变量名称和构造复杂签名字符串的动机。它只会使代码变得缓慢和混乱。切面不能替代调试器,尤其是在生产环境中使用时。但好吧,这是一个品味问题。我的碰巧不一样。这个问题仍然有效,这就是我回答它的原因。
  • @kriegaex 这样做的目的是记录应用程序特定层的所有方法调用。签名没有提供参数名称,这使得日志语句模棱两可。
  • 如果你想一分钟你之前的陈述,你会发现它是错误的。方法签名由其参数类型唯一定义,将其与任何给定类的所有其他同名方法区分开来。参数名称与识别方法完全无关,没有歧义。如果您说它是眼睛糖果,而您的大脑只是发现它更易于阅读,那很好。但是没有参数名称就模棱两可:没有。
  • 参数对于日志使用者来说是模棱两可的,他们可能对应用程序没有深入的了解。日志使用者不必参考我的源代码来理解参数。如果这些值正在被 ELK 堆栈或类似的东西使用,则参数名称非常重要。

标签: java spring aspectj spring-aop


【解决方案1】:

简单的问题,简单的答案:不。

更新:也许您想知道为什么需要投射。除了方法签名,还有其他签名类型吗?哦,是的,有。例如。如果您使用within(SomeClass),您可能会遇到以下任何签名类型:

  • 方法
  • 构造函数
  • 类初始化器
  • 字段
  • 建议执行
  • catch 子句
  • 锁定/解锁(一种相当特殊的情况,如果方面是使用-Xjoinpoints:synchronization 编译的,则捕获同步块)

这是一个小例子:

驱动程序应用:

package de.scrum_master.app;

public class Application {
  private String name;

  public Application(String name) {
    this.name = name;
  }

  public static void main(String[] args) {
    Application application = new Application("my app");
    synchronized (application) {
      try {
        application.doSomething("foo", 11, false);
      }
      catch (RuntimeException e) {}
    }
  }

  private void doSomething(String string, int i, boolean b) {
    throw new RuntimeException("oops");
  }
}

Aspect 应该被拦截的通知执行:

package de.scrum_master.aspect;

public aspect MyOtherAspect {
  before() : execution(* main(..)) {}
}

方面打印签名类型:

package de.scrum_master.aspect;

import de.scrum_master.app.Application;

public aspect MyAspect {
  before() : within(Application) || within(MyOtherAspect) {
    System.out.println(thisJoinPoint);
    System.out.println("    " + thisJoinPoint.getSignature().getClass().getSimpleName());
  }
}

控制台日志:

staticinitialization(de.scrum_master.app.Application.<clinit>)
    InitializerSignatureImpl
staticinitialization(de.scrum_master.aspect.MyOtherAspect.<clinit>)
    InitializerSignatureImpl
preinitialization(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
initialization(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
execution(de.scrum_master.aspect.MyOtherAspect())
    ConstructorSignatureImpl
adviceexecution(void de.scrum_master.aspect.MyOtherAspect.before())
    AdviceSignatureImpl
execution(void de.scrum_master.app.Application.main(String[]))
    MethodSignatureImpl
call(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
preinitialization(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
initialization(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
execution(de.scrum_master.app.Application(String))
    ConstructorSignatureImpl
set(String de.scrum_master.app.Application.name)
    FieldSignatureImpl
lock(lock(Object))
    LockSignatureImpl
call(void de.scrum_master.app.Application.doSomething(String, int, boolean))
    MethodSignatureImpl
execution(void de.scrum_master.app.Application.doSomething(String, int, boolean))
    MethodSignatureImpl
call(java.lang.RuntimeException(String))
    ConstructorSignatureImpl
handler(catch(RuntimeException))
    CatchClauseSignatureImpl
unlock(unlock(Object))
    UnlockSignatureImpl

顺便说一句,每个*Impl 类都实现了相应的签名接口。

【讨论】:

  • 感谢我今晚失眠,我只是添加了一些示例代码+更多解释。享受!请原谅我更喜欢原生 AspectJ 语法。很容易转换为@AspectJ 样式。
  • 非常有用,谢谢!我没有意识到有这么多不同的可用切入点。我只需要方法级别的 AOP。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多