字节码应用场景 AOP 技术、Lombok 去除重复代码插件、动态修改 class 文件等 字节码技术优势 Java 字节码增强指的是在 Java 字节码生成之后,对其进行修改,增强其功能,这种方式相当于对应用程序的二进制文件进行修改,Java 字节码增强主要是为了减少冗余代码,提高性能等 实现字节码增强的主要步骤为: 修改字节码,在内存中获取到原来的字节码,然后通过一些工具(如 ASM,Javaasist)来修改它的byte[]数组,得到一个新的byte数组 使修改后的字节码生效

自定义 ClassLoader 来加载修改后的字节码 替换掉原来的字节码,在 JVM 加载用户的 Class 时,拦截,返回修改后的字节码,或者在运行时,使用Instrumentation.redefineClasses 方法来替换掉原来的字节码 常见的字节码操作类库 BCEL Byte Code Engineering Library(BCEL),这是Apache Software Foundation的 Jakarta 项目的一部分,BCEL 是 Java classworking 广泛使用的一种框架,它可以让您深入jvm汇编语言进行类库操作的细节,BCEL 与 javassist 有不同的处理字节码方法,BCEL 在实际的 JVM 指令层次上进行操作(BCEL 拥有丰富的 JVM 指令集支持)而 javassist 所强调的是源代码级别的工作 ASM 是一个轻量级 Java 字节码操作框架,直接涉及到JVM底层的操作和指令,高性能,高质量 CGLB 生成类库,基于ASM实现 javassist 是一个开源的分析、编辑和创建 Java 字节码的类库,性能较 ASM 差,跟 CGLIB 差不多,但是使用简单,很多开源框架都在使用它 Javassist 中最为重要的是 ClassPool、CtClass 、CtMethod、CtField ClassPool:一个基于HashMap实现的 CtClass 对象容器,其中键是类名称,值是表示该类的 CtClass 对象,默认的ClassPool 使用与底层 JVM 相同的类路径,因此在某些情况下,可能需要向 ClassPool 添加类路径或类字节 CtClass:表示一个类,这些 CtClass 对象可以从 ClassPool 获得 CtMethods:表示类中的方法 CtFields :表示类中的字段 优势: 比反射开销小、性能高 操作字节码可以动态生成新的类,动态修改类(添加、删除、修改属性或方法) javassist 外层 API 和反射类似 主要有 CtClass、CtMethod、CtField 组成,执行反射中的 java.lang.Class、java.lang.reflect.Method、 java.lang.reflect.Method .Field 中的操作 劣势: 不支持 JDK5 的新语法,包括泛型、枚举,不支持注解修改 不支持数组初始化 不支持内部类和匿名类 不支持 continue 和 break 动态创建类 public static void main(String[] args) throws CannotCompileException, NotFoundException, IOException { ClassPool pool = ClassPool.getDefault(); // 创建User CtClass userClass = pool.makeClass("com.kernel.entity.User"); // 创建属性 CtField nameField = CtField.make("private String name;", userClass); CtField ageField = CtField.make("private Integer age;", userClass); // 添加属性 userClass.addField(nameField); userClass.addField(ageField); // 创建方法 CtMethod getName = CtMethod.make("public String getName() {return name;}", userClass); CtMethod setName = CtMethod.make("public void setName(String name) {this.name = name;}", userClass); // 添加方法 userClass.addMethod(getName); userClass.addMethod(setName); // 创建构造器 CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.String"), pool.get("java.lang.Integer")}, userClass); // 设置内容 constructor.setBody("{this.name = name;this.age = age;}"); // 添加构造器 userClass.addConstructor(constructor); userClass.writeFile("D:\Codes\Java\Performance\jvm-day03\src\main\java\com\kernel\test"); } 动态添加并执行方法 public static void main(String[] args) { try { ClassPool pool = ClassPool.getDefault(); // 读取com.kernel.User CtClass userClass = pool.get("com.kernel.User"); // 创建方法,设置方法返回值 CtMethod method = new CtMethod(CtClass.voidType, "sum", new CtClass[] { CtClass.intType, CtClass.intType }, userClass); // 设置方法内容 method.setBody("{System.out.println("sun:" + ($1 + $2));}"); // 添加方法 userClass.addMethod(method); userClass.writeFile("D:\Codes\Java\Performance\jvm-day03\src\main\java\com\kernel\test"); // 动态执行方法 Class clazz = userClass.toClass(); Object newInstance = clazz.newInstance(); // 获得方法 Method sumMethod = clazz.getDeclaredMethod("sum", int.class, int.class); sumMethod.invoke(newInstance, 2, 5); } catch (Exception e) { e.printStackTrace(); } }