欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java-ASM

程序员文章站 2022-05-07 10:30:47
...

我们知道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类并调用打印语句。

 

 

  • asm.rar (17.2 KB)
  • 下载次数: 1

推荐阅读