Java-ASM

我们知道Java是静态语言,而python、ruby是动态语言,Java程序一旦写好很难在运行时更改类的行为,而python、ruby可以。

不过基于bytecode层面上我们可以做一些手脚,来使Java程序多一些灵活性和Magic,ASM就是这样一个应用广泛的开源库。

ASMisaJavabytecodemanipulationframework.Itcanbeusedtodynamicallygeneratestubclassesorotherproxyclasses,

directlyinbinaryform,ortodynamicallymodifyclassesatloadtime,i.e.,justbeforetheyareloadedintotheJavaVirtualMachine.

ASM完成了BCEL和SERP同样的功能,但ASM

只有30多k,而后两者分别是350k和150k。apache真是越来越过气了。

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

Java代码

1.importjava.io.FileOutputStream;

2.importjava.io.PrintStream;

3.importorg.objectweb.asm.ClassWriter;

4.importorg.objectweb.asm.MethodVisitor;

5.importorg.objectweb.asm.Opcodes;

6.importorg.objectweb.asm.Type;

7.importorg.objectweb.asm.commons.GeneratorAdapter;

8.importorg.objectweb.asm.commons.Method;

9.

10.publicclassHelloworldextendsClassLoaderimplementsOpcodes{

11.

12.public staticvoid main(finalStringargs[])throwsException{

13.

14.//createsaClassWriterfortheExamplepublicclass,

15.//whichinheritsfromObject

16.

17.ClassWriter cw = newClassWriter(0);

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

19.MethodVisitormw=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,

20.null);

21.mw.visitVarInsn(ALOAD,0);

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

23.mw.visitInsn(RETURN);

24.mw.visitMaxs(1,1);

25.mw.visitEnd();

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

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

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

29."Ljava/io/PrintStream;");

30.mw.visitLdcInsn("Helloworld!");

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

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

33.mw.visitInsn(RETURN);

34.mw.visitMaxs(2,2);

35.mw.visitEnd();

36.byte[]code=cw.toByteArray();

37.FileOutputStreamfos=newFileOutputStream("Example.class");

38.fos.write(code);

39.fos.close();

40.Helloworldloader=newHelloworld();

41.ClassexampleClass=loader

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

43.exampleClass.getMethods()[0].invoke(null,newObject[]{null});

44.//------------------------------------------------------------------------

45.//SameexamplewithaGeneratorAdapter(moreconvenientbutslower)

46.//------------------------------------------------------------------------

47.

48.cw=newClassWriter(ClassWriter.COMPUTE_MAXS);

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

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

51.GeneratorAdaptermg=newGeneratorAdapter(ACC_PUBLIC,m,null,null,

52.cw);

53.mg.loadThis();

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

55.mg.returnValue();

56.mg.endMethod();

57.m=Method.getMethod("voidmain(String[])");

58.mg=newGeneratorAdapter(ACC_PUBLIC+ACC_STATIC,m,null,null,cw);

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

60..getType(PrintStream.class));

61.mg.push("Helloworld!");

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

63..getMethod("voidprintln(String)"));

64.mg.returnValue();

65.mg.endMethod();

66.cw.visitEnd();

67.code=cw.toByteArray();

68.loader=newHelloworld();

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

70.exampleClass.getMethods()[0].invoke(null,newObject[]{null});

71.}

72.}

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

猜你喜欢

转载自alex4java.iteye.com/blog/2288644
ASM