有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java是否可以使用ByteBuddy建议机制将本机方法封装在线程中?

我试图延迟写入单独线程中的socket,以使用javaagent模拟网络堆栈中的延迟。使用ByteBuddy,我设法装饰了本机java.net.SocketOutputStream::writeSocket0。然而,这样做,我暂停了当前线程,这不是我想要实现的。为了避免这个问题,我考虑创建一个线程,从中可以调用本机方法。不幸的是,我对ByteBuddy的了解仍然相当有限,我没有找到实现这一点的方法。我的最佳尝试如下所示:

//premain function
public static void premain(final String agentArgs, final Instrumentation instrumentation) {
    try{
        BootLoaderInjector.inject(DelayedExecutor.class);
        long duration = 100;

        new AgentBuilder.Default()
            .with(new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE))
            .with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
            .with(AgentBuilder.TypeStrategy.Default.REBASE)
            .enableNativeMethodPrefix("somePrefix")
            .with(AgentBuilder.Listener.StreamWriting.toSystemError().withErrorsOnly())
            .ignore(nameStartsWith("net.bytebuddy."))
            .type(named("java.net.SocketOutputStream"))
            .transform((transformer, typeDescription, classLoader, javaModule) ->
                transformer.method(named("socketWrite0"))
                    .intercept(
                        Advice.withCustomMapping().bind(Duration.class, duration)
                        .to(DelayInterceptor.class)
                )
            )
            .installOn(instrumentation);
    }
    catch (Throwable t){
        System.err.printf(t.getMessage());
    }
}

// interceptor class
public class DelayInterceptor {
    @Advice.OnMethodEnter
    public static void intercept(@SuperCall Callable<?> caller, @Duration long duration) {
        DelayedExecutor.execute(callable, duration);
    }
}

// execute the intercepted method in a new thread with a delay
public class DelayedExecutor implements Runnable {
    private final Callable<?> callable;
    private final long delay;

    private DelayedExecutor(Callable<?> callable, long delay) {
        this.callable = callable;
        this.delay = delay;
    }

    public static void execute(Callable<?> callable, long delay){
        new Thread(new DelayedExecutor(callable, delay)).start();
    }

    @Override
    public void run() {
        try {
            Thread.sleep(this.delay);
            this.callable.call();
        } catch (Exception ignore) {}
    }
}

但是,这失败了,因为@Callable不是AdviceAPI的一部分

不使用这些建议似乎会造成严重的限制。实际上,使用MethodDelegation会引发以下错误:

Registration of auxiliary types was disabled: net.bytebuddy.implementation.auxiliary.MethodCallProxy@3206bfce

有没有一种方法可以使用ByteBuddy的AdviceAPI将函数调用包装到块中

编辑

为了更清楚地说明问题并解决答案建议,下面是BootLoaderInjector.inject的实现,它显示了如何根据ClassInjector.UsingUnsafe.ofBootLoader()将类型添加到引导加载程序类加载程序中:

public class BootLoaderInjector {
    public static void inject(Class<?> targetClass) {
        try {
            ClassInjector.UsingUnsafe.ofBootLoader().inject(singletonMap(
                    new TypeDescription.ForLoadedType(targetClass),
                    ClassFileLocator.ForClassLoader.read(targetClass)
            ));
        } catch (Throwable e){
            System.out.println("Something went terribly wrong: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

共 (1) 个答案

  1. # 1 楼答案

    您需要注册一个InjectionStrategy来将这些必需的类型注入到目标类加载器中。例如,对于引导加载程序,这可能是一个UsingInstrumentation。更有效地,但依赖于JVM内部API,您还可以使用UsingUnsafe