首页 > 其他 > 详细

java- ASM 字节码操控框架

时间:2014-02-07 03:15:18      阅读:410      评论:0      收藏:0      [点我收藏+]

我们知道Java是静态语言,而pythonruby是动态语言,Java程序一旦写好很难在运行时更改类的行为,而python、ruby可以。
不过基于bytecode层面上我们可以做一些手脚,来使Java程序多一些灵活性和Magic,ASM就是这样一个应用广泛的开源库。

可以把它看成反射的一种替代方案,但效率更高更灵活,当然也更难.


ASM is a Java bytecode manipulation framework. It can be used to dynamically generatestub classes or other proxy classes,
directly in binary form, or to dynamically modify classes at load time, i.e., justbefore they are loaded into the Java
Virtual Machine.

ASM完成了
BCELSERP同样的功能,但ASM
只有30多k,而后两者分别是350k和150k。apache真是越来越过气了。

让我们来看一个ASM的简单例子Helloworld.java,它生成一个Example类和一个main方法,main方法打印"Hello world!"语句:

Java代码

import java.io.FileOutputStream;  

import java.io.PrintStream;  


import org.objectweb.asm.ClassWriter;  

import org.objectweb.asm.MethodVisitor;  

import org.objectweb.asm.Opcodes;  

import org.objectweb.asm.Type;  

import org.objectweb.asm.commons.GeneratorAdapter;  

import org.objectweb.asm.commons.Method;  


publicclass Helloworld extends ClassLoader implements Opcodes {  


publicstaticvoid main(final String args[]) throws Exception {  


// creates a ClassWriter for the Example public class,

// which inherits from Object


    ClassWriter cw = new ClassWriter(0);  

    cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);  

    MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null,  

null);  

    mw.visitVarInsn(ALOAD, 0);  

    mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");  

    mw.visitInsn(RETURN);  

    mw.visitMaxs(1, 1);  

    mw.visitEnd();  

    mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main",  

"([Ljava/lang/String;)V", null, null);  

    mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out",  

"Ljava/io/PrintStream;");  

    mw.visitLdcInsn("Hello world!");  

    mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println",  

"(Ljava/lang/String;)V");  

    mw.visitInsn(RETURN);  

    mw.visitMaxs(2, 2);  

    mw.visitEnd();  

byte[] code = cw.toByteArray();  

    FileOutputStream fos = new FileOutputStream("Example.class");  

    fos.write(code);  

    fos.close();  

    Helloworld loader = new Helloworld();  

    Class exampleClass = loader  

        .defineClass("Example", code, 0, code.length);  

    exampleClass.getMethods()[0].invoke(null, new Object[] { null });  


// ------------------------------------------------------------------------

// Same example with a GeneratorAdapter (more convenient but slower)

// ------------------------------------------------------------------------


    cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);  

    cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);  

    Method m = Method.getMethod("void <init> ()");  

    GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null,  

        cw);  

    mg.loadThis();  

    mg.invokeConstructor(Type.getType(Object.class), m);  

    mg.returnValue();  

    mg.endMethod();  

    m = Method.getMethod("void main (String[])");  

    mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);  

    mg.getStatic(Type.getType(System.class), "out", Type  

        .getType(PrintStream.class));  

    mg.push("Hello world!");  

    mg.invokeVirtual(Type.getType(PrintStream.class), Method  

        .getMethod("void println (String)"));  

    mg.returnValue();  

    mg.endMethod();  

    cw.visitEnd();  

    code = cw.toByteArray();  

    loader = new Helloworld();  

    exampleClass = loader.defineClass("Example", code, 0, code.length);  

    exampleClass.getMethods()[0].invoke(null, new Object[] { null });  

  }  

}

我们看到上面的例子分别使用ASM的MethodVisitorGeneratorAdapter两种方式来动态生成Example类并调用打印语句。


本文出自 “人生如梦初醒” 博客,请务必保留此出处http://withacker.blog.51cto.com/3568061/1355103

java- ASM 字节码操控框架

原文:http://withacker.blog.51cto.com/3568061/1355103

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!