如何在运行时发出和执行Java字节码?

如何在运行时发出和执行Java字节码?,第1张

如何在运行时发出和执行Java字节码?

这是使用ObjectWeb ASM(我推荐的一个库)构成的一个有效的“ hello world” :

package hello;import java.lang.reflect.Method;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.Label;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Oppres;public class HelloWorldASM implements Oppres {    public static byte[] compile(String name) {        ClassWriter cw = new ClassWriter(0);        MethodVisitor mv;        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "hello/HelloWorld", null,     "java/lang/Object", null);        cw.visitSource("HelloWorld.java", null);        { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(4, l0); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",         "()V"); mv.visitInsn(RETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "Lhello/HelloWorld;", null, l0, l1,         0); mv.visitMaxs(1, 1); mv.visitEnd();        }        { mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",         "([Ljava/lang/String;)V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(7, l0); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",         "Ljava/io/PrintStream;"); mv.visitLdcInsn(String.format("Hello, %s!", name)); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",         "(Ljava/lang/String;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(8, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2,         0); mv.visitMaxs(2, 1); mv.visitEnd();        }        cw.visitEnd();        return cw.toByteArray();    }    public static class DynamicClassLoader extends ClassLoader {        public Class<?> define(String className, byte[] bytepre) { return super.defineClass(className, bytepre, 0, bytepre.length);        }    };    public static void main(String[] args) throws Exception {        DynamicClassLoader loader = new DynamicClassLoader();        Class<?> helloWorldClass = loader.define("hello.HelloWorld",     compile("Test"));        Method method = helloWorldClass.getMethod("main", String[].class);        method.invoke(null, (Object) new String[] {});    }}

为了生成代码,我发现了非常有用的Eclipse插件字节码大纲。尽管您可以像这样使用ASMifier(包含在ASM中):

ClassReader cr = new ClassReader(new FileInputStream("HelloWorld.class"));cr.accept(new ASMifierClassVisitor(new PrintWriter(System.out)), 0);

在运行时,如果需要获取所

Class
创建类的对象,则可以通过扩展类加载器并发布(例如,通过其他方法)将该
defineClass
方法并以字节数组形式提供类来加载类,如例。

您还可以使用接口来处理创建的类,例如以下示例:

package hello;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.Label;import org.objectweb.asm.MethodVisitor;import org.objectweb.asm.Oppres;public class HelloWorldPlugin implements Oppres {    public static interface Plugin {        void sayHello(String name);    }    public static byte[] compile() {        ClassWriter cw = new ClassWriter(0);        MethodVisitor mv;        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "hello/MyClass", null,     "java/lang/Object",     new String[] { "hello/HelloWorldPlugin$Plugin" });        cw.visitInnerClass("hello/HelloWorldPlugin$Plugin",     "hello/HelloWorldPlugin", "Plugin", ACC_PUBLIC + ACC_STATIC  + ACC_ABSTRACT + ACC_INTERFACE);        { mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(5, l0); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>",         "()V"); mv.visitInsn(RETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "Lhello/MyClass;", null, l0, l1, 0); mv.visitMaxs(1, 1); mv.visitEnd();        }        { mv = cw.visitMethod(ACC_PUBLIC, "sayHello",         "(Ljava/lang/String;)V", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(9, l0); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out",         "Ljava/io/PrintStream;"); mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitLdcInsn("Hello, "); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder",         "<init>", "(Ljava/lang/String;)V"); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",         "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder",         "toString", "()Ljava/lang/String;"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",         "(Ljava/lang/String;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(10, l1); mv.visitInsn(RETURN); Label l2 = new Label(); mv.visitLabel(l2); mv.visitLocalVariable("this", "Lhello/MyClass;", null, l0, l2, 0); mv.visitLocalVariable("name", "Ljava/lang/String;", null, l0, l2,         1); mv.visitMaxs(4, 2); mv.visitEnd();        }        cw.visitEnd();        return cw.toByteArray();    }    public static class DynamicClassLoader extends ClassLoader {        public DynamicClassLoader(ClassLoader parent) { super(parent);        }        public Class<?> define(String className, byte[] bytepre) { return super.defineClass(className, bytepre, 0, bytepre.length);        }    };    public static void main(String[] args) throws Exception {        DynamicClassLoader loader = new DynamicClassLoader(Thread     .currentThread().getContextClassLoader());        Class<?> helloWorldClass = loader.define("hello.MyClass", compile());        Plugin plugin = (Plugin) helloWorldClass.newInstance();        plugin.sayHello("Test");    }}

玩得开心。

PS:如果不够清晰,我可以在代码中添加注释。我不是因为答案已经太长了。不过,我对您的建议是尝试对其进行调试。



欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5478741.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-12
下一篇 2022-12-12

发表评论

登录后才能评论

评论列表(0条)

保存