使用Byte Buddy拦截Object.class到String()方法



我正在使用Byte Buddy拦截一些JDK方法,System.class和Thread.class很好,但在java.lang.Object上不起作用。我正在JDK8上运行测试,它没有抛出任何错误。

final public class AgentBootstrap {
public static void premain(String agentArgs, Instrumentation inst) throws Exception {
try {
new AgentBuilder.Default()
.with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
.with(AgentBuilder.InitializationStrategy.NoOp.INSTANCE)
.with(AgentBuilder.TypeStrategy.Default.REBASE)
.enableNativeMethodPrefix("$$mynative_")
.ignore(ElementMatchers.none())
.with(
new AgentBuilder.Listener.Filtering(
new StringMatcher("java.lang.Object", StringMatcher.Mode.EQUALS_FULLY),
AgentBuilder.Listener.StreamWriting.toSystemOut()))
.type(ElementMatchers.is(Object.class))
.transform(new Transformer() {
@Override
public Builder<?> transform(Builder<?> builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule module) {
return builder.method(ElementMatchers.named("toString")).intercept(FixedValue.value("HELLO BYTE BUDDY!"));
}
})
.installOn(inst);
}
catch (Exception e) {
e.printStackTrace();
}
}
}

我尝试使用Javassist,转换java.lang.Object的方法是成功的。有人知道为什么它在Object.class上不起作用吗?

您想要使用

  • CCD_ 1为了避免违反重新转换规则的结构类文件更改
  • 建议API,以便在不添加新方法的情况下将代码插入到现有方法中
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.asm.Advice;
import java.lang.instrument.Instrumentation;
import static net.bytebuddy.agent.builder.AgentBuilder.RedefinitionStrategy.RETRANSFORMATION;
import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC;
import static net.bytebuddy.matcher.ElementMatchers.*;
class Scratch {
public static class ToStringAdvice {
@Advice.OnMethodEnter(skipOn = Advice.OnDefaultValue.class)
public static boolean before() {
// Skip original method execution (false is the default value for boolean)
return false;
}
@Advice.OnMethodExit
public static void after(@Advice.Return(readOnly = false, typing = DYNAMIC) Object returnValue) {
// Set fixed return value
returnValue = "HELLO BYTE BUDDY!";
}
}
public static void premain(String agentArgs, Instrumentation inst) {
new AgentBuilder.Default()
.disableClassFormatChanges()
.with(RETRANSFORMATION)
.with(AgentBuilder.RedefinitionStrategy.Listener.StreamWriting.toSystemError())
.with(AgentBuilder.Listener.StreamWriting.toSystemError().withTransformationsOnly())
.with(AgentBuilder.InstallationListener.StreamWriting.toSystemError())
.ignore(none())
.type(is(Object.class))
.transform((builder, typeDescription, classLoader, module) ->
builder.visit(
Advice
.to(ToStringAdvice.class)
.on(named("toString"))
)
)
.installOn(inst);
}
public static void main(String[] args) throws Exception {
Instrumentation instrumentation = ByteBuddyAgent.install();
premain("", instrumentation);
instrumentation.retransformClasses(Object.class);
System.out.println(new Object());
}
}

这是有效的。。。

[Byte Buddy] BEFORE_INSTALL net.bytebuddy.agent.builder.AgentBuilder$Default$ExecutingTransformer@3bfdc050 on sun.instrument.InstrumentationImpl@1bce4f0a
[Byte Buddy] REDEFINE BATCH #0 [1 of 1 type(s)]
[Byte Buddy] TRANSFORM java.lang.Object [null, null, loaded=true]
[Byte Buddy] REDEFINE COMPLETE 1 batch(es) containing 1 types [0 failed batch(es)]
[Byte Buddy] INSTALL HELLO BYTE BUDDY! on HELLO BYTE BUDDY!
[Byte Buddy] TRANSFORM java.lang.Object [null, null, loaded=true]
HELLO BYTE BUDDY!

但我认为在操作JDK核心类之前应该三思而后行。查看上面的日志。你注意到在日志行

[Byte Buddy] INSTALL HELLO BYTE BUDDY! on HELLO BYTE BUDDY!

正在打印两个对象,它们显然使用了您刚才建议的方法?所以要小心!