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
不是Advice
API的一部分
不使用这些建议似乎会造成严重的限制。实际上,使用MethodDelegation会引发以下错误:
Registration of auxiliary types was disabled: net.bytebuddy.implementation.auxiliary.MethodCallProxy@3206bfce
有没有一种方法可以使用ByteBuddy的Advice
API将函数调用包装到块中
编辑
为了更清楚地说明问题并解决答案建议,下面是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 楼答案
您需要注册一个
InjectionStrategy
来将这些必需的类型注入到目标类加载器中。例如,对于引导加载程序,这可能是一个UsingInstrumentation
。更有效地,但依赖于JVM内部API,您还可以使用UsingUnsafe