Java 字节伙伴成员替换引发IllegalStateException错误

Java 字节伙伴成员替换引发IllegalStateException错误,java,instrumentation,byte-buddy,Java,Instrumentation,Byte Buddy,我正在尝试使用byte buddy编写java检测代理。我的目标是用我自己的代理调用替换java标准库方法调用。有人建议我使用Byte Buddy的MemberSubstitution来实现这一点。我使用了SO提出的问题作为参考 我正在使用Intellij IDEA进行编码。我的代理代码被拆分为多个文件,如下所示: MyFirstAgent.java public class MyFirstAgent { public static void premain(String agentA

我正在尝试使用byte buddy编写java检测代理。我的目标是用我自己的代理调用替换java标准库方法调用。有人建议我使用Byte Buddy的
MemberSubstitution
来实现这一点。我使用了SO提出的问题作为参考

我正在使用Intellij IDEA进行编码。我的代理代码被拆分为多个文件,如下所示:

MyFirstAgent.java

public class MyFirstAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        new AgentBuilder.Default()
                .type(ElementMatchers.any())
                .transform(new ByteBuddyTransformer())
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(inst);
}
public class ByteBuddyTransformer implements AgentBuilder.Transformer {

    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                            ClassLoader classLoader, JavaModule javaModule) {

        try {
            return builder.visit(MemberSubstitution.relaxed()
                    .method(named("add"))
                    .replaceWith(MyClass.class.getMethod("printLine"))
                    .on(any()));

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return builder;
    }
}
public class MyClass {
    public boolean printLine(){
        System.out.println("This is the proxy!");
        return true;
    }
}
public class Main {
    public static void main(String[] args) {
        ClassToMonitor classToMonitor = new ClassToMonitor();
        classToMonitor.bar();
    }
}
package com.company;

import java.util.ArrayList;
import java.util.Arrays;

public class ClassToMonitor {
    public void bar() {
// create an empty array list with an initial capacity
        ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
        arrlist.add(15);

// print all the elements available in list
        for (Integer number : arrlist) {
            System.out.println("Number = " + number);
        }
    }
}
ByteBuddyTransformer.java

public class MyFirstAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        new AgentBuilder.Default()
                .type(ElementMatchers.any())
                .transform(new ByteBuddyTransformer())
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(inst);
}
public class ByteBuddyTransformer implements AgentBuilder.Transformer {

    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                            ClassLoader classLoader, JavaModule javaModule) {

        try {
            return builder.visit(MemberSubstitution.relaxed()
                    .method(named("add"))
                    .replaceWith(MyClass.class.getMethod("printLine"))
                    .on(any()));

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return builder;
    }
}
public class MyClass {
    public boolean printLine(){
        System.out.println("This is the proxy!");
        return true;
    }
}
public class Main {
    public static void main(String[] args) {
        ClassToMonitor classToMonitor = new ClassToMonitor();
        classToMonitor.bar();
    }
}
package com.company;

import java.util.ArrayList;
import java.util.Arrays;

public class ClassToMonitor {
    public void bar() {
// create an empty array list with an initial capacity
        ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
        arrlist.add(15);

// print all the elements available in list
        for (Integer number : arrlist) {
            System.out.println("Number = " + number);
        }
    }
}
我想在另一个Intellij IDEA项目中使用的应用程序如下所示:

Main.java

public class MyFirstAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        new AgentBuilder.Default()
                .type(ElementMatchers.any())
                .transform(new ByteBuddyTransformer())
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(inst);
}
public class ByteBuddyTransformer implements AgentBuilder.Transformer {

    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                            ClassLoader classLoader, JavaModule javaModule) {

        try {
            return builder.visit(MemberSubstitution.relaxed()
                    .method(named("add"))
                    .replaceWith(MyClass.class.getMethod("printLine"))
                    .on(any()));

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return builder;
    }
}
public class MyClass {
    public boolean printLine(){
        System.out.println("This is the proxy!");
        return true;
    }
}
public class Main {
    public static void main(String[] args) {
        ClassToMonitor classToMonitor = new ClassToMonitor();
        classToMonitor.bar();
    }
}
package com.company;

import java.util.ArrayList;
import java.util.Arrays;

public class ClassToMonitor {
    public void bar() {
// create an empty array list with an initial capacity
        ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
        arrlist.add(15);

// print all the elements available in list
        for (Integer number : arrlist) {
            System.out.println("Number = " + number);
        }
    }
}
ClassToMonitor.java

public class MyFirstAgent {

    public static void premain(String agentArgs, Instrumentation inst) {

        new AgentBuilder.Default()
                .type(ElementMatchers.any())
                .transform(new ByteBuddyTransformer())
                .with(AgentBuilder.Listener.StreamWriting.toSystemOut())
                .with(AgentBuilder.TypeStrategy.Default.REDEFINE)
                .installOn(inst);
}
public class ByteBuddyTransformer implements AgentBuilder.Transformer {

    @Override
    public DynamicType.Builder<?> transform(DynamicType.Builder<?> builder, TypeDescription typeDescription,
                                            ClassLoader classLoader, JavaModule javaModule) {

        try {
            return builder.visit(MemberSubstitution.relaxed()
                    .method(named("add"))
                    .replaceWith(MyClass.class.getMethod("printLine"))
                    .on(any()));

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return builder;
    }
}
public class MyClass {
    public boolean printLine(){
        System.out.println("This is the proxy!");
        return true;
    }
}
public class Main {
    public static void main(String[] args) {
        ClassToMonitor classToMonitor = new ClassToMonitor();
        classToMonitor.bar();
    }
}
package com.company;

import java.util.ArrayList;
import java.util.Arrays;

public class ClassToMonitor {
    public void bar() {
// create an empty array list with an initial capacity
        ArrayList<Integer> arrlist = new ArrayList<Integer>(5);

// use add() method to add elements in the list
        arrlist.add(15);

// print all the elements available in list
        for (Integer number : arrlist) {
            System.out.println("Number = " + number);
        }
    }
}

如果需要,我可以提供完整的错误消息。另外,我对Java和插装一般来说是新手,所以我可能缺少一些基本的东西,请原谅,如果是这样的话,请指出。

要让替换工作,目标方法需要接受与替换方法相同的参数,在您的例子中是一个
int
。此外,由于您正在调用一个成员,因此类的隐式第一个参数需要是接收方类型,即
ArrayList
或任何超类型,甚至
Object
。此外,您的替换方法需要是静态的:

public class MyClass {
  public static boolean printLine(Object ignored, int ignored2){
    System.out.println("This is the proxy!");
    return true;
  }
}

成员替代仍然没有想象的那么灵活。但是,如果需要,您已经可以使用
链接的
步骤注入自定义字节码。

要进行替换,目标方法需要接受与替换方法相同的参数,在您的示例中是
int
。此外,由于您正在调用一个成员,因此类的隐式第一个参数需要是接收方类型,即
ArrayList
或任何超类型,甚至
Object
。此外,您的替换方法需要是静态的:

public class MyClass {
  public static boolean printLine(Object ignored, int ignored2){
    System.out.println("This is the proxy!");
    return true;
  }
}
成员替代仍然没有想象的那么灵活。但是,如果您需要的话,您可以使用
chained
步骤注入自定义字节码