Java 动态生成二进制字节码
来源:互联网 发布:com.au域名注册 编辑:程序博客网 时间:2024/06/05 15:02
Java动态代理过程中,会动态生成二进制字节码(只在内存中),该生成过程究竟是怎样的,我来一探究竟。
class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的。
1、类加载器
a.定义一个 Programmer类: public class Programmer { public void code() { System.out.println("I'm a Programmer,Just Coding....."); } } b.自定义一个类加载器: public class MyClassLoader extends ClassLoader { public Class<?> defineMyClass( byte[] b, int off, int len) { return super.defineClass(b, off, len); } } c.然后编译成Programmer.class文件,在程序中读取字节码,然后转换成相应的class对象,再实例化: public class MyTest { public static void main(String[] args) throws IOException { //读取本地的class文件内的字节码,转换成字节码数组 File file = new File("."); InputStream input = new FileInputStream(file.getCanonicalPath()+"\\bin\\samples\\Programmer.class"); byte[] result = new byte[1024]; int count = input.read(result); // 使用自定义的类加载器将 byte字节码数组转换为对应的class对象 MyClassLoader loader = new MyClassLoader(); Class clazz = loader.defineMyClass( result, 0, count); //测试加载是否成功,打印class 对象的名称 System.out.println(clazz.getCanonicalName()); //实例化一个Programmer对象 Object o= clazz.newInstance(); //new Programmer(); try { //调用Programmer的code方法 clazz.getMethod("code", null).invoke(o, null); } catch (IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { e.printStackTrace(); } } } 以上代码演示了,通过字节码加载成class对象的能力。
上面只是使用类加载器来手动加载class文件到内存中(class文件是存在的),那么class文件如何动态生成呢?
2、在运行期生成二进制字节码
由于JVM通过字节码的二进制信息加载类的,那么,如果我们在运行系统中,遵循Java编译系统组织.class文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据加载转换成对应的类,这样,就完成了在代码中,动态创建一个类的能力了。
在运行时期可以按照Java虚拟机规范对class文件的组织规则生成对应的二进制字节码。当前有很多开源框架可以完成这些功能,如ASM,Javassist。
1)Java字节码生成开源框架介绍:ASM
ASM 是一个 Java 字节码操控框架。它能够以二进制形式修改已有类或者动态生成类。ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为。ASM 从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类。不过ASM在创建class字节码的过程中,操纵的级别是底层JVM的汇编指令级别,这要求ASM使用者要对class组织结构和JVM汇编指令有一定的了解。
使用ASM框架提供了ClassWriter 接口,通过访问者模式进行动态创建Programmer.class字节码:
public class MyGenerator { public static void main(String[] args) throws IOException { System.out.println(); ClassWriter classWriter = new ClassWriter(0); // 通过visit方法确定类的头部信息 classWriter.visit(Opcodes.V1_7,// java版本 Opcodes.ACC_PUBLIC,// 类修饰符 "Programmer", // 类的全限定名 null, "java/lang/Object", null); //创建构造函数 MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(Opcodes.ALOAD, 0); mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>","()V"); mv.visitInsn(Opcodes.RETURN); mv.visitMaxs(1, 1); mv.visitEnd(); // 定义code方法 MethodVisitor methodVisitor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "code", "()V", null, null); methodVisitor.visitCode(); methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); methodVisitor.visitLdcInsn("I'm a Programmer,Just Coding....."); methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); methodVisitor.visitInsn(Opcodes.RETURN); methodVisitor.visitMaxs(2, 2); methodVisitor.visitEnd(); classWriter.visitEnd(); // 使classWriter类已经完成 // 将classWriter转换成字节数组写到文件里面去 byte[] data = classWriter.toByteArray(); File file = new File("D://Programmer.class"); //生成字节码文件 FileOutputStream fout = new FileOutputStream(file); fout.write(data); fout.close(); } }
2)Java字节码生成开源框架介绍JavassistJavassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶滋)所创建的。它已加入了开放源代码JBoss应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。javassist是jboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。
生成Programmer.class字节码:
public class MyGenerator { public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); //创建Programmer类 CtClass cc= pool.makeClass("com.samples.Programmer"); //定义code方法 CtMethod method = CtNewMethod.make("public void code(){}", cc); //插入方法代码 method.insertBefore("System.out.println(\"I'm a Programmer,Just Coding.....\");"); cc.addMethod(method); //保存生成的字节码 cc.writeFile("d://temp"); } }
参考:
Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM) (清晰,浅显)
- Java 动态生成二进制字节码
- java 动态代理 生成字节码文件
- javassist学习:动态创建二进制Java类二进制字节码并通过反射调用的示例
- asm动态生成字节码
- Java 将字符串动态生成字节码的一种方法
- Java字节码的动态生成和增强
- Java 将字符串动态生成字节码的一种方法
- java动态生成源文件和字节码方式
- 动态生成Java字节码之java字节码框架ASM的学习
- 动态生成java字节码之java字节码框架asm
- java二进制字节码实例详解
- java-动态代理-jdk代理、cglib代理、生成字节码文件.
- Java字节、二进制、字节流、字符
- ASM JAVA字节码生成架构
- Java生成字节码的意思
- ASM的一个例子(动态字节码生成) (Java高级编程(J2SE综合)) - [Matrix - 与 Java 共舞]
- java动态编程-操作字节码
- spring AOP动态代理和CGLIB字节码生成
- 谁的青春不似梦,谁的梦里不青春
- 如何给ViewPager的条目添加渐变动画
- C/C++使用心得:enum与int的相互转换
- ECharts纵坐标显示时间1
- PHP类数组式访问(ArrayAccess接口)
- Java 动态生成二进制字节码
- 分糖果 (蓝桥杯)
- 2017安卓面试问题总结
- 构建对空表分配空间的SQL命令。
- jQuery开发插件模板
- 主成分分析(PCA)原理详解
- c++第3次作业
- Linux系统无法识别RTL8723网卡
- plsql锁表解锁