如果我有以下
Class
名为Dog
public class Dog {
private String name = "Spike";
private int age = 3;
public Dog() {}
public String getName() {
return name;
}
}
我如何声明 ByteBuddy 在
javaagent
中使用以重新定义 Dog
Class
以提供返回 getAge
的方法 int
?
GOAL:所需的(有效的)
Class
应该如下所示,并且可以通过执行dog.getAge()
来调用
public class Dog {
private String name = "Spike";
private int age = 3;
public Dog() {}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
尝试 1:我尝试将语法更改为我理解的正确语法(下面找到 PitBullInterceptor.class)
new AgentBuilder.Default()
.redefine(Dog.class)
.defineMethod("getAge", int.class, Method.PUBLIC)
.intercept(MethodDelegation.to(PitBullInterceptor.class))
.installOn(instrumentation);
我在尝试中遇到以下问题
The method redefine(Class<Dog>) is undefined for the type AgentBuilder.Default
这基本上是一个语法错误。我不确定使用哪个
DynamicTypes
或 MethodDelegations
/ElementMaters
来配置 Agentbuilder
来执行这种类型的重新定义/变基,正如 Rafael Winterhalter 所描述的那样
尝试 2:我尝试将它与 ByteBuddyAgent.install 一起使用
public static void main(String[] args) throws Exception {
ByteBuddyAgent.install();
new ByteBuddy()
.redefine(Dog.class)
.defineMethod("getValue", int.class, Method.PUBLIC)
.intercept(MethodDelegation.to(PitBullInterceptor.class))
.make()
.load(Dog.class.getClassLoader(), ClassReloadingStrategy.fromInstalledAgent())
.getLoaded()
.newInstance();
}
public static class PitBullInterceptor {
private static int age = 1;
public static int getValue() {
return age;
}
}
产生错误:
java.lang.UnsupportedOperationException: class redefinition failed: attempted to add a method
尝试 3:最后,我尝试使用内置代理这样做
public static void premain(String arguments, Instrumentation instrumentation) {
new AgentBuilder.Default()
.disableClassFormatChanges().with(RetransformationStrategy.RETRANSFORM)
.with(new ByteBuddy()
.redefine(PitBull.class)
.method(ElementMatchers.named("getValue"))
.intercept(MethodDelegation.to(PitBullInterceptor.class))
.make()
.load(Dog.class.getClassLoader()))
.installOn(instrumentation);
}
public static class PitBull {
private String name = "Roxy";
public String getName() {
return name;
}
}
public static class PitBullInterceptor {
private static String value = "WoofWoofWoof";
public static String getValue() {
return value;
}
}
出品:
java -javaagent:agent.jar -jar app.jar
Exception in thread "main" java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:491)
at java.instrument/sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:503)
Caused by: java.lang.IllegalStateException: Class already loaded: class io.xxx.agent.boss.Agent$PitBull
at net.bytebuddy.dynamic.loading.ByteArrayClassLoader.load(ByteArrayClassLoader.java:363)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default$WrappingDispatcher.load(ClassLoadingStrategy.java:367)
at net.bytebuddy.dynamic.loading.ClassLoadingStrategy$Default.load(ClassLoadingStrategy.java:148)
at net.bytebuddy.dynamic.TypeResolutionStrategy$Passive.initialize(TypeResolutionStrategy.java:101)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6317)
at net.bytebuddy.dynamic.DynamicType$Default$Unloaded.load(DynamicType.java:6305)
at io.xxx.agent.boss.Agent.premain(Agent.java:21)
... 6 more
*** java.lang.instrument ASSERTION FAILED ***: "result" with message agent load/premain call failed at t:\workspace\open\src\java.instrument\share\native\libinstrument\JPLISAgent.c line: 422
FATAL ERROR in native method: processing of -javaagent failed, processJavaStart failed
由于JVM 的限制,您不能添加、删除或修改现有类的成员。你必须要么
或者,您可以使用支持这种修改的第三方 JVM(参见:JetBrains runtime with the Enhanced class redefinition flag),但假设这需要普遍运行,它会有点负担。