当前位置: 首页 > 知识库问答 >
问题:

使用byte-buddy (System.nanoTime())截取和更改静态本机方法的返回值

霍财
2023-03-14

我想改变为任意 Java 程序调用 System.nanoTime() 时会发生什么(我想将时间移回以帮助容器检查点/恢复用例)。每当调用System.nanoTime()时,我都想运行原始的System.nanoTime(),然后可能返回一个不同的值。我正在尝试使用字节伙伴和 JVM 仪表代理来执行此操作(根据此处和此处)。

这是我的尝试:

public final class TimeShifter {
    private TimeShifter() {}

    private static final Class<?> INTERCEPTOR_CLASS = TimeShiftedSystem.class;

    public static void premain(String _arg, Instrumentation instrumentation) throws Exception {
        injectBootstrapClasses(instrumentation);
        new AgentBuilder.Default()
                .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
                .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .ignore(
                        new AgentBuilder.RawMatcher.ForElementMatchers(
                                ElementMatchers.nameStartsWith("net.bytebuddy.")
                                        .or(ElementMatchers.isSynthetic())
                                        .or(ElementMatchers.nameStartsWith("my.package.name.")),
                                ElementMatchers.any(),
                                ElementMatchers.any()))
                .with(
                        new AgentBuilder.Listener.Filtering(
                                new StringMatcher("java.lang.System", StringMatcher.Mode.EQUALS_FULLY),
                                AgentBuilder.Listener.StreamWriting.toSystemOut()))
                .type(ElementMatchers.named("java.lang.System"))
                .transform((builder, type, classLoader, module) ->
                        // https://stackoverflow.com/questions/49487148/redefine-rebase-native-method
                        builder.method(ElementMatchers.named("nanoTime"))
                        .intercept(Advice.to(TimeShiftedSystem.class)))
                .installOn(instrumentation);
    }

    private static void injectBootstrapClasses(Instrumentation instrumentation) throws IOException {
        File temp = Files.createTempDirectory("tmp").toFile();
        temp.deleteOnExit();

        ClassInjector.UsingInstrumentation.of(
                        temp, ClassInjector.UsingInstrumentation.Target.BOOTSTRAP, instrumentation)
                .inject(Collections.singletonMap(
                        new TypeDescription.ForLoadedType(INTERCEPTOR_CLASS),
                        ClassFileLocator.ForClassLoader.read(INTERCEPTOR_CLASS)));
    }
}

public final class TimeShiftedSystem {
    private TimeShiftedSystem() {}

    @Advice.OnMethodExit
    public static long nanoTime(@Advice.Return long originalReturnValue) {
        System.out.println("originalReturnValue = " + originalReturnValue);

        return originalReturnValue - 1000;
    }
}

但这失败了:

[Byte Buddy] DISCOVERY java.lang.System [null, module java.base, loaded=true]
[Byte Buddy] ERROR java.lang.System [null, module java.base, loaded=true]
java.lang.IllegalStateException: Cannot call super (or default) method for public static native long java.lang.System.nanoTime()
    at net.bytebuddy.implementation.SuperMethodCall$Appender.apply(SuperMethodCall.java:133)

有什么办法可以实现这一点?我试过的其他东西:

  • 使用 MethodDelegation.to 而不是 Advice.to 然后在 TimeShiftedSystem#nanoTime() 中调用 System.nanoTime() - 这似乎是第一次调用原始 nanoTime,但立即进入堆栈溢出。
  • 使用 MethodDelegation.to 而不是 Advice.to 和 @Origin 方法方法作为参数。似乎根本没有被调用(如果还使用了@RuntimeType注释,则不调用)。
  • 使用 enabledNativeMethodPrefix(“native”) - 不执行任何操作。

任何帮助都非常感谢。

共有1个答案

哈扬
2023-03-14

解决方案是设置

    .with(AgentBuilder.TypeStrategy.Default.REBASE)
    .enableNativeMethodPrefix("native")

在< code>AgentBuilder上,而不是< code>AgentBuilder上。type strategy . default . redefine (并将< code > ' Can-Set-Native-Method-Prefix ':true 添加到我的jar清单中)。这使我能够让< code > timeshift dsystem 处理以下建议:

@Advice.OnMethodExit
public static void nanoTime(@Advice.Return(readOnly = false) long returnValue) {
    System.out.println("Called with " + returnValue);
    returnValue = 42;
}
 类似资料:
  • 我正在尝试记录“object.wait”方法调用的计数。截取“public final native void wait(long timeout)”对ByteBuddy无效。我做了一些测试: test1,test2打印错误:java.lang.IllegalStateException:无法为公共最终void java.lang.Object.Wait(long,int)调用超级(或默认)方法抛

  • 当一个方法完成时,我试图使用Byte Buddy来执行一些额外的逻辑。以下是示例代码: 当我把代表团和。第二次调用时,此实例的原始调用方将丢失来自“proxyClient”对象的返回值,该对象以前用于调用它的方法调用。我是不是用错了? 基本上,我希望在方法的末尾添加一些附加逻辑(在原始方法内部或添加另一个方法调用并不重要),但同时保留原始方法调用的返回值。

  • 我正在具体的类上创建动态代理。因为Java的普通代理类只对接口有帮助,所以我选择了cglib。 我使用带有MethodInterceptor的增强器类来拦截我的代理的方法,我能够拦截除静态方法之外的所有方法调用。 有什么方法可以使用cglib拦截对静态方法的调用吗?

  • 使用或,是否有任何方法可以拦截对对象的非静态方法的调用,或者至少是对单例对象的非静态方法的调用? 以下类提供了一个示例: 但是,上面的类只提供了一个私有构造函数,因此不能对其进行扩展。使用返回部分模拟(spy)也不会起作用,因为类不提供无参数构造函数。 想要的嘲弄能以其他任何方式实现吗?对于非单例类可以这样做吗?

  • 我正在使用Spring并试图用AspectJ编写示例应用程序。我需要学习如何拦截静态方法调用。在我的示例中,我尝试截取main方法,如下所示: Spring配置文件: 主要方法: 协会本身: 但是当我运行应用程序时,唯一的字符串正在打印。

  • 问题内容: 我一直在寻找“如何在运行时向方法添加注释”的答案,发现了一个名为Byte Buddy的出色工具,可以使用它,但仍然无法按需使用。我确定它必须能够从这个问题做到这一点Byte Buddy可以在运行时创建字段和方法注释吗? 上这堂课: 和此代码: 向 类 添加注释很容易。但是对于 方法而言 ,似乎不更改方法实现是不可能的。 我敢肯定,我只是做得不好,但是不幸的是,当方法 没有代码更改 而只