Methods Javassist-为什么我可以';在执行过程中被拦截后,是否替换方法体?

Methods Javassist-为什么我可以';在执行过程中被拦截后,是否替换方法体?,methods,call,instrumentation,javassist,bytecode-manipulation,Methods,Call,Instrumentation,Javassist,Bytecode Manipulation,我试图用instrument替换主类中声明的方法。这段代码将在执行过程中拦截所有方法调用,但它不会替换某个方法的方法体(change) BeanMain.java package application; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.NotFoundException; import javassis

我试图用
instrument
替换主类中声明的方法。这段代码将在执行过程中拦截所有方法调用,但它不会替换某个方法的方法体(
change

BeanMain.java

package application;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.expr.ExprEditor;
import javassist.expr.MethodCall;

public class BeanMain {
    private Bean bean;

    public BeanMain(){
        bean = new Bean("old_a", "old_b");
    }

    public void print(){
        System.out.format("\n%-25s %5s  %5s\n", "[BeanMain]", bean.getA(), bean.getB());

    }

    public void change(String pre){
        bean.setParam(pre+"A", pre+"B");
    }

    public static void main(String[] args) throws NotFoundException, CannotCompileException {
        ClassPool pool = ClassPool.getDefault();
        CtClass ctClass = pool.get("application.BeanMain");
        ctClass.instrument(new ExprEditor(){
            @Override
            public void edit(MethodCall m) throws CannotCompileException {
                System.out.println(m.getMethodName());
                if(m.getMethodName().equals("change"))
                    m.replace("{System.out.println(\"$1\"); $_ = $proceed($$);}");
            }
        });
        BeanMain inst = new BeanMain();
        inst.print();
        inst.change("new_");
        inst.print();
    }
}
java

package application;

public class Bean {
    private String a;
    private String b;

    public Bean(){}

    public Bean(String a, String b) {
        this.a = a;
        this.b = b;
    }

    public String getA() {
        return a;
    }

    public void setA(String a) {
        this.a = a;
    }

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    public void setParam(String a, String b){
        this.a = a;
        this.b = b;
    }

    public void doSomething(){
        System.out.println("Doing something.");
    }
}

我的问题类加载相关吗?

你必须下定决心。是否要替换方法调用或方法声明的主体?假设我要替换方法调用,在这种情况下
replace()
method是否受到限制?如果要替换方法调用,“它不会替换方法主体”不是错误。很难说更换电话是否有效。名为
change
的方法的唯一方法调用发生在已运行的
main
方法中。插装不会取代方法的执行,只会取代后续的执行。因此,根据您最后一句话,我能插装BeanMain类加载的类所调用的方法吗?我从未为此使用过Javassist,所以我不能说任何关于
CtClass.instrument
,但原则上,HotSpot JVM的检测工具能够替换后续调用的所有方法。因此,假设Javassist在其上运行,这应该是可能的。如果在插入指令后再次调用
main
方法,它甚至应该可以工作。