详解Java中的字节码增强技术
作者:深色風信子
字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。本文将通过示例详细说说Java的字节码增强技术,需要的可以参考一下
1.字节码增强技术
字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。
2.常见技术
技术分类 | 类型 |
---|---|
静态增强 | AspectJ |
动态增强 | ASM、Javassist、Cglib、Java Proxy |
3.ASM
<dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.4</version> </dependency>
ASM Core API可以类比解析XML文件中的SAX方式,不需要把这个类的整个结构读取进来,就可以用流式的方法来处理字节码文件。好处是非常节约内存,但是编程难度较大。然而出于性能考虑,一般情况下编程都使用Core API。在Core API中有以下几个关键类:
技术分类 | 类型 |
---|---|
ClassReader | 用于读取已经编译好的.class文件。 |
ClassWriter | 用于重新构建编译后的类,如修改类名、属性以及方法,也可以生成新的类的字节码文件。 |
Visitor类 | 如上所述,CoreAPI根据字节码从上到下依次处理,对于字节码文件中不同的区域有不同的Visitor,比如用于访问方法的MethodVisitor、用于访问类变量的FieldVisitor、用于访问注解的AnnotationVisitor等。为了实现AOP,重点要使用的是MethodVisitor。 |
3.1 测试 Main
package com.xu.test; /** * @author Administrator */ public class Main { public void print() { System.out.println("ASM"); } }
3.2 测试 CustomerClassVisitor
package com.xu.test; import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; /** * ASM 字节码增强技术 * * @author Administrator */ public class CustomerClassVisitor extends ClassVisitor implements Opcodes { public CustomerClassVisitor(ClassVisitor api) { super(ASM9, api); } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { cv.visit(version, access, name, signature, superName, interfaces); } @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, descriptor, signature, exceptions); if (StringUtils.equals("print", name) && mv != null) { mv = new CustomerMethodVisitor(mv); } return mv; } class CustomerMethodVisitor extends MethodVisitor implements Opcodes { public CustomerMethodVisitor(MethodVisitor api) { super(ASM9, api); } @Override public void visitCode() { super.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("start"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); } @Override public void visitInsn(int opcode) { if ((opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) || opcode == Opcodes.ATHROW) { mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("end"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); } mv.visitInsn(opcode); } } }
3.3 测试 Test
package com.xu.test; import java.io.File; import java.io.FileOutputStream; import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; /** * @author Administrator */ public class Test { public static void main(String[] args) throws Exception { ClassReader reader = new ClassReader("com/xu/test/Main"); ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); // 处理 ClassVisitor visitor = new CustomerClassVisitor(writer); reader.accept(visitor, ClassReader.SKIP_DEBUG); // 输出 File file = new File("target\\classes\\com\\xu\\test\\Main.class"); FileOutputStream stream = new FileOutputStream(file); stream.write(writer.toByteArray()); stream.close(); // 测试 Class<?> cls = Class.forName("com.xu.test.Main"); Main main = (Main) cls.getDeclaredConstructor().newInstance(); main.print(); } }
到此这篇关于详解Java中的字节码增强技术的文章就介绍到这了,更多相关Java字节码增强内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!