Java 是否可以用ByteBuddy而不是被调用的方法检测方法调用?

Java 是否可以用ByteBuddy而不是被调用的方法检测方法调用?,java,scala,aspectj,byte-buddy,Java,Scala,Aspectj,Byte Buddy,我想替换一些AspectJ代码,这些代码保护一些用户代码对java.lang.System的调用。 java.lang.System不能/不应该检测 使用AspectJ,解决方案是插入调用代码,如以下示例所示。应保护的代码将被检测,而不允许的代码被检测 @Around("call(public long java.lang.System.currentTimeMillis()) && within(io.someuserdomain..*) && !within(

我想替换一些AspectJ代码,这些代码保护一些用户代码对
java.lang.System
的调用。
java.lang.System
不能/不应该检测

使用AspectJ,解决方案是插入调用代码,如以下示例所示。应保护的代码将被检测,而不允许的代码被检测

@Around("call(public long java.lang.System.currentTimeMillis()) && within(io.someuserdomain..*) && !within(io.someotherdomain..*))
def aroundSystemcurrentTimeMillis(wrapped: ProceedingJoinPoint): Long = {
      throw new IllegalStateException("must not call System.currentTimeMillis in usercode")
}

使用ByteBuddy有没有同样的方法?到目前为止,我只找到了有关如何为被调用方而不是调用方插入指令的示例。

您当前可以通过注册
成员替换来替换方法或字段访问,但与AspectJ相比,这些功能仍然有限。例如,不可能像示例代码中那样引发异常。但是,您可以委托给包含引发异常的代码的方法:

MemberSubstitution.relaxed()
  .method(named("currentTimeMillis"))
  .replaceWith(MyClass.class.getMethod("throwException"))
  .in(any());
上述替换将用对以下成员的调用替换任何方法调用:

public class MyClass {
  public static long throwException() {
    throw new IllegalStateException();
  }
}

替换将应用于访问者应用到的任何方法。您可以注册一个
AgentBuilder.Default
来构建Java代理,或者查看Byte Buddy的构建插件。

为什么要用ByteBuddy替换AspectJ?AspectJ运行时小得多,没有其他依赖项。您试图通过切换工具来解决的问题是什么?对不起,我忘记量化我之前的陈述:AspectJ运行时有120K字节,打包依赖项为3.2M。比较当前版本的JAR,JAR大小相差27.5倍,有利于AspectJ。这并不意味着它是更好的工具,但对于您想要做的事情,它非常适合。如果使用编译时编织,甚至可以在方面中声明编译器警告或错误,以便在方面检测到非法方法调用时使编译失败。如果CTW是一个选项而不是LTW,我会这样做,因为在运行时检测它是次优的。@kriegaex好问题。我们正在使用另一个从aspectj切换到bytebuddy(kamon)的库。在我们的代码库中,我们谨慎地使用aspectj,并希望避免维护多个检测框架。至于讨论的用例——如果这是我唯一需要插装的地方,我会选择aspectj,因为它允许更大的灵活性。但是我当然对aspectj有偏见,我对bytebuddy是新手。在我从aspectj转换到bytebuddy的其他地方,bytebuddy中插装声明的类型安全性比aspectj好。我很惊讶你这么说类型安全性。事实上,我从没有足够经验正确使用AspectJ的人那里看到了很多糟糕的方面代码,所以也许这就是它的来源。话虽如此,我承认我对AspectJ的偏见,因为我一直在使用它,我确实同意ByteBuddy是一个强大的工具,毫无疑问,你也会用它优雅地解决你的问题。拉斐尔的回答在我看来非常好,他在这里提供了巨大的支持,因此,作为ByteBuddy的作者。:-)祝你好运!谢谢你的快速回复!不幸的是,我一直在应用这个例子
newbytebuddy().redefinite(evilocode.getClass).visit(MemberSubstitution.relaxed.method(ElementMatchers.hasMethodName(“currentTimeMillis”)).replacetwith(Thrower.getClass.getMethod(“throweException”).on(ElementMatchers.any()).make()
这会引发
java.lang.IllegalStateException:无法在上调用公共长抛出器$.throweException()[]
这里有详细的要点:嗯,使用scala对象的静态方法,ByteBuddy发现由于对象的实例字段,参数不兼容,因此IllegalStateException似乎是个问题……通过声明一个普通java类,不会引发异常……我让示例运行时没有失败,但我的测试仍然没有失败失败(检测未捕获呼叫)bytebuddy确实更改了一些内容:
OpenJDK 64位服务器VM警告:共享仅支持引导加载程序类,因为已追加引导类路径
,但未调用抛出程序
预期抛出异常java.lang.RuntimeException,但未引发异常
您是否注册了AgentBuilder。是否在代理中设置侦听器,以查看类是否已正确插入指令?