将代理程序附加到运行进程时,bytebuddy转换器似乎没有生效

时间:2017-11-30 10:56:50

标签: byte-buddy

我要附加的程序代码如下。

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

有什么建议吗?

1 个答案:

答案 0 :(得分:0)

您似乎没有为代理使用重新定义。您可以使用以下方法激活它:

new AgentBuilder.Default()
  .with(RedefinitionStrategy.RETRANSFORMATION)
  .disableClassFormatChanges();

大多数JVM都需要最后一部分(除了动态代码演进VM,HotSpot的自定义构建之外)。它告诉Byte Buddy不添加字段或方法,大多数虚拟机不支持。

在这种情况下,不再可能调用FixedValue所不需要的方法的原始实现。通常,Byte Buddy的用户在创建应用动态类转换的代理时会利用Advice