【问题标题】:Can I pass className and methodName at runtime to ClassVisitor() and methodVisitor() in ASM parser after started the server?启动服务器后,我可以在运行时将 className 和 methodName 传递给 ASM 解析器中的 ClassVisitor() 和 methodVisitor() 吗?
【发布时间】:2013-07-09 13:43:02
【问题描述】:

我已经开始学习(我是新手),用于编译器项目的 ASM API。我正在使用 java Instrumentation 和 ASM ByteCode Library 来开发 Javaagent。

我通过属性传递类名和方法名。我的目标是在运行时更改我的类名和方法名(意味着在服务器启动或调用 premain() 之后)。

但是,它只适用于在启动服务器之前传递的 className 或 packageName。

我知道,在调用 javaagent (premain()) 时,ASM 为给定包/类的方法设置访问者。

即使在服务器启动或调用 premain() 之后,我也想访问特定的类和方法。

如果有人对此提供帮助,那将非常有帮助。

这是我目前正在运行的程序。

        public class AddPrintlnAgent implements ClassFileTransformer {

    public static void premain(String agentArgs, Instrumentation inst) {
     Properties prop = new Properties();

    try {
        prop.load(new FileInputStream("C:\\locator.properties"));

    } catch (FileNotFoundException e) {

        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    inst.addTransformer(new AddPrintlnAgent());
}

public byte[] transform(ClassLoader loader, String className,
        Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
        byte[] classfileBuffer) throws IllegalClassFormatException {

    byte[] retVal = null;

    if (className.equals(className)) {
        ClassWriter cw = new ClassWriter(0); 
        ClassVisitor ca = new MyClassAdapter(cw); 
        ClassReader cr = new ClassReader(classfileBuffer); 
        cr.accept(ca, 0); 
        retVal = cw.toByteArray();
    }
    return retVal;
}

public class MyClassAdapter extends ClassNode implements Opcodes { 
    private ClassVisitor cv; 
     Properties prop = new Properties();
    public MyClassAdapter(ClassVisitor cv) { 
        this.cv = cv;  

    } 
    @Override 
    public void visitEnd() { 
        try {
            prop.load(new FileInputStream("C:\\locator.properties"));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
         for (MethodNode mn : (List<MethodNode>) methods) {
             if (mn.name.equals(prop.getProperty("methodName").trim())) {
            InsnList il = new InsnList();

            il.add(new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
            il.add(new LdcInsnNode(prop.getProperty("message")));
            il.add(new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", 
                        "println", "(Ljava/lang/String;)V"));
            mn.instructions.insert(il);

            mn.maxStack +=2;                    
            }
        }
        accept(cv); 
    } 

}

}

提前致谢

萨蒂什·V·J

【问题讨论】:

  • 如果我错了,请纠正我,但if (className.equals(className)) { 应该总是返回 true,从而为每个类重写你的字节码。另外,“更改我的类名和方法名”到底是什么意思?您是否打算更改某些类和方法的名称?

标签: java compilation bytecode java-bytecode-asm


【解决方案1】:

您应该清理您的代码。在您的 premain 方法中,您将属性文件加载到 Properties 对象中,但该实例从未使用过。相反,您在每次 visitEnd() 调用时将该文件重新加载到另一个 Properties 实例中。我不确定这是否真的是你想要的。

但是,转换器是在类加载期间调用的,而不是已经加载的类。您可以尝试重新转换或重新定义加载的类,但检测不支持在加载后更改类或方法名称。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2012-01-17
    • 2020-09-14
    相关资源
    最近更新 更多