asm动态生成class,并且动态加载执行
本人初学,我也搞得不是很明白,目前只做出这个demo, asm那些操作具体是什么意思,请查看asm的api 。
性能方面,没测试
废话不多说了,直接上代码
首先把自定义的类加器搞上来
?
package net;public class MyClassLoader extends ClassLoader{ @SuppressWarnings("unchecked") public Class defineClassByName(String name,byte[] b,int off,int len){ Class clazz = super.defineClass(name,b, off, len); return clazz; } }??
下面上动态生成class的代码,visit方法的第一个参数为class的版本号,jdk1.6的用49,目前没有找到每个jdk所对应的class文件版本号。
?
package net;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.PrintStream;import java.lang.reflect.InvocationTargetException;import org.objectweb.asm.ClassWriter;import org.objectweb.asm.Opcodes;import org.objectweb.asm.Type;import org.objectweb.asm.commons.GeneratorAdapter;import org.objectweb.asm.commons.Method;public class AsmDemo{ @SuppressWarnings("unchecked") public static void main(String[] args) { /*生成类文件的结构,代码现在是这样 * public class HelloWorld{ * * } */ ClassWriter cw=new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(49, Opcodes.ACC_PUBLIC, "HelloWorld", null, "java/lang/Object", null); Method m=Method.getMethod("void <init> ()"); GeneratorAdapter ga=new GeneratorAdapter(Opcodes.ACC_PUBLIC,m,null,null,cw); ga.loadThis(); ga.invokeConstructor(Type.getType(Object.class), m); ga.returnValue(); ga.endMethod(); /* * 在HelloWorld中添加main方法,在main方法中添加代码,代码现在是这样子 * public class HelloWorld{ * public static void mian(String[] args){ * System.out.println("Hello World!"); * } * } */ m = Method.getMethod("void main (String[])"); ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, m, null, null, cw); ga.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); ga.push("Hello World!"); ga.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)")); ga.returnValue(); ga.endMethod(); cw.visitEnd(); /* * 这个方法用于后面的类动态加载测试,HelloWorld中的结构现在已经变成 * public class HelloWorld{ * public static void mian(String[] args){ * System.out.println("Hello World!"); * } * public void doSomething(){ * System.out.println("动态生成,动态加载调用方法"); * } * } */ m=Method.getMethod("void doSomething()"); ga=new GeneratorAdapter(Opcodes.ACC_PUBLIC,m,null,null,cw); ga.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class)); ga.push("动态生成,动态加载调用方法"); ga.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println(String)")); ga.returnValue(); ga.endMethod(); MyClassLoader mcl=new MyClassLoader(); //利用自定义的类加载器把生成类文件加载到jvm 。 byte[] bytes=cw.toByteArray(); //返回的对象时被加载类的class Class hw=mcl.defineClassByName("HelloWorld", bytes, 0, bytes.length); try { //利用反射创建对象 Object o=hw.newInstance(); java.lang.reflect.Method method= o.getClass().getMethod("doSomething"); method.invoke(o); /*把文件生成的class文件写入磁盘 File.separator为文件分隔符(知道的勿喷) * ,它会根据操作系统不同,而自动转换,比直接写成\\这种通用性强。 * 这个路径原来一般写成d:\\HelloWorld.class */ File file=new File("d:"+File.separator+"HelloWorld.class"); FileOutputStream fos=new FileOutputStream(file); fos.write(cw.toByteArray()); fos.flush(); fos.close(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}?
?运行这个控制台输出为
动态生成,动态加载调用方法
?
然后我们发现d多了个class文件,打开命令提示符切换到d盘,输入java HelloWorld
控制台输出
Hello World!
源码和所需Jar包在附件中