我要附加的程序代码如下。
public class Foo {
}
public class TestEntry {
public TestEntry() {
}
public static void main(String[] args) throws Exception {
try
{
while(true)
{
System.out.println(new Foo().toString());
Thread.sleep(1000);
}
}
catch(Exception e)
{}
}
}
我尝试做的是让Foo.toString()通过使用以下代理返回'test'。
public class InjectionAgent {
public InjectionAgent() {
}
public static void agentmain(String args, Instrumentation inst) throws Exception
{
System.out.println("agentmain Args:" + args);
new AgentBuilder.Default()
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("test"));
}
}).installOn(inst);
}
public static void premain(String args, Instrumentation inst) throws Exception
{
System.out.println("premain Args:" + args);
new AgentBuilder.Default()
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.method(ElementMatchers.named("toString"))
.intercept(FixedValue.value("test"));
}
}).installOn(inst);
}
}
我注意到,当我使用-javaagent方式时它成功了,而attach方法失败了,这里是附加代码。
public class Injection {
public Injection() {
}
public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException, InterruptedException {
VirtualMachine vm = null;
String agentjarpath = args[0];
vm = VirtualMachine.attach(args[1]);
vm.loadAgent(agentjarpath, "This is Args to the Agent.");
vm.detach();
}
}
我尝试将AgentBuilder.Listener.StreamWriting.toSystemOut()添加到代理程序,附加后,TestEntry的输出显示
[Byte Buddy] DISCOVERY Foo [sun.misc.Launcher$AppClassLoader@33909752,null,loaded = true]
[Byte Buddy] TRANSFORM Foo [sun.misc.Launcher$AppClassLoader@33909752,null,loaded = true]
[Byte Buddy] COMPLETE Foo [sun.misc.Launcher$AppClassLoader@33909752,null,loaded = true]
富@ 7f31245a
富@ 6d6f6e28
富@ 135fbaa4
富@ 45ee12a7
富@ 330bedb4
==================================更新============ ========================= 我在Foo中定义了一个公共方法'Bar',就像这样
public class Foo {
public String Bar()
{
return "Bar";
}
}
然后我试图让Foo.Bar()以下列方式返回“modified”:
public static void agentmain(String args, Instrumentation inst) throws Exception
{
System.out.println("agentmain Args:" + args);
premain(args, inst);
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.disableClassFormatChanges()
.with(AgentBuilder.Listener.StreamWriting.toSystemOut())
.type(ElementMatchers.named("Foo"))
.transform(new AgentBuilder.Transformer() {
@Override
public Builder<?> transform(Builder<?> arg0, TypeDescription arg1,
ClassLoader arg2, JavaModule arg3) {
return arg0.visit(Advice.to(InjectionTemplate.class).on(ElementMatchers.named("Bar")));
}
})
.installOn(inst);
}
static class InjectionTemplate {
@Advice.OnMethodExit
static void exit(@Advice.Return String self) {
System.out.println(self.toString() + " " + self.getClass().toString());
self = new String("modified");
}
}
但是我收到了这个错误:
java.lang.IllegalStateException:无法在1处写入只读参数类java.lang.String
有什么建议吗?
答案 0 :(得分:0)
您似乎没有为代理使用重新定义。您可以使用以下方法激活它:
new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.disableClassFormatChanges();
大多数JVM都需要最后一部分(除了动态代码演进VM,HotSpot的自定义构建之外)。它告诉Byte Buddy不添加字段或方法,大多数虚拟机不支持。
在这种情况下,不再可能调用FixedValue
所不需要的方法的原始实现。通常,Byte Buddy的用户在创建应用动态类转换的代理时会利用Advice
。