淘客客怎么做自己的网站,重庆建设工程信息网官网安全员证书查询,重庆建设工程信息网官网入口网页,wordpress页面设计外贸字节码操作
什么是字节码
Java字节码#xff08;Java bytecode#xff09;是Java虚拟机#xff08;JVM#xff09;执行的一种虚拟指令格式。它是由Java编译器生成的#xff0c;基于栈的指令集#xff0c;用于在Java虚拟机上执行。字节码文件包含了JVM能够识别的指令Java bytecode是Java虚拟机JVM执行的一种虚拟指令格式。它是由Java编译器生成的基于栈的指令集用于在Java虚拟机上执行。字节码文件包含了JVM能够识别的指令当JVM执行这些指令时会通过解释器逐条读取字节码文件中的指令并将其解释成机器码执行。
JAVA动态性的实现方式
字节码操作反射
运行时操作字节码可以让我们实现如下功能
动态生成新的类动态改变某个类的结构添加/删除/修改 新的属性/方法
运行时操作字节码的优势反射开销小性能高
什么是Javassist
Javassist是一个开源的分析、编辑和创建Java字节码的类库。它是jboss的一个子项目主要优点在于简单且快速。它允许开发者直接使用Java编码的形式而无需了解虚拟机指令就能动态地改变类的结构或动态生成类。 Javassist提供了一组简单易用的API使开发者能够动态地创建、修改、分析Java类而无需关心底层的字节码细节。 它的核心API包括ClassPool和CtClass其中ClassPool用于跟踪和控制所操作的类而CtClass则提供了检查类数据如字段和方法以及在类中添加新字段、方法和构造函数等功能。 Javassist的功能与jdk自带的反射功能类似但更为强大。它能在Java程序运行时定义新的类并加载到JVM中也可以在JVM加载时修改一个类文件。 此外Javassist还用于生成新的Java类以适应不同的需求例如在实现ORM框架时或者用于编写Mock框架以便在测试过程中控制类的行为以及实现性能监控工具对方法的执行时间进行统计和分析诊断潜在问题。
Javassist常用API
Javassist是一个功能强大的Java字节码操作和分析库它提供了一组常用的API来简化对字节码的修改和生成。以下是一些Javassist的常用API及其功能描述
模块方法描述ClassPool模块---ClassPool.getDefault()获取默认的ClassPool对象它用于存储和操作类信息。-pool.get(className)根据类名获取对应的CtClass对象。-pool.makeClass(name)创建一个新的类。CtClass模块---ctClass.setName(name)设置类的名称。-ctClass.setSuperclass(superclass)设置类的父类。-ctClass.getDeclaredMethods()获取类声明的所有方法。-ctClass.getDeclaredFields()获取类声明的所有字段。-ctClass.makeClassFile()获取该类的ClassFile对象用于更底层的字节码操作。-ctClass.writeFile()将修改后的类写入文件。CtMethod模块---ctMethod.setName(name)设置方法名称。-ctMethod.setModifier(modifier)设置方法修饰符。-ctMethod.setBody(body)设置方法的字节码体。-ctMethod.insertBefore(src)在方法体前插入字节码。-ctMethod.insertAfter(src)在方法体后插入字节码。CtField模块---ctField.setName(name)设置字段名称。-ctField.setType(type)设置字段类型。-ctField.setModifier(modifier)设置字段修饰符。-ctField.setInitialValue(value)设置字段的初始值。CtConstructor-与CtMethod类似用于操作类的构造函数。javassist.bytecode 模块-ClassFile、MethodInfo、CodeAttribute等类提供了对字节码的低级别访问接口允许直接读取和修改字节码指令。其他---new Annotation()创建注解。-new Bytecode()直接操作字节码。
这些API只是Javassist功能的一部分Javassist还提供了许多其他功能如接口修改、异常处理、导入类等。使用时建议参考Javassist的官方文档或相关教程以获取更详细的信息和示例代码
测试案例
案例1
package com.demo.demo1;import javassist.*;import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;/*** 是用javassist创建一个UserDo,使用构造方法设置值打印结果** author Anna.* date 2024/4/4 17:32*/
public class JavassistDemo {public static void main(String[] args) throws Exception {// 创建ClassPool对象ClassPool classPool ClassPool.getDefault();// 创建一个新的类CtClass ctClass classPool.makeClass(com.demo.entity.UserDo);// 创建属性CtField fieldName CtField.make(private String name;, ctClass);CtField fieldAge CtField.make(private Integer age;, ctClass);// 将属性添加到类中ctClass.addField(fieldName);ctClass.addField(fieldAge);// 创建get方法CtMethod getName CtMethod.make(public String getName(){return this.name;}, ctClass);CtMethod getAge CtMethod.make(public Integer getAge(){return this.age;}, ctClass);// 将方法添加到类中ctClass.addMethod(getName);ctClass.addMethod(getAge);// 创建构造器CtConstructor constructor1 CtNewConstructor.make(public UserDo(){}, ctClass);CtConstructor constructor2 CtNewConstructor.make(public UserDo(String name,Integer age){this.name name; this.age age;}, ctClass);// 添加构造器ctClass.addConstructor(constructor1);ctClass.addConstructor(constructor2);// 写入对应文件String path JavassistDemo.class.getResource(/).getPath();ctClass.writeFile(path);// 使用反射获取对象并初始化调用getName方法URLClassLoader urlClassLoader URLClassLoader.newInstance(new URL[]{new URL(file:/ path)});Class? clazz urlClassLoader.loadClass(com.demo.entity.UserDo);Object o1 clazz.getDeclaredConstructor(String.class, Integer.class).newInstance(张三, 20);// 调用getName方法Method getName1 clazz.getMethod(getName);System.out.println(getName1.invoke(o1));}
}执行结果 案例2
package com.demo.demo2;import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;import java.lang.reflect.Method;/*** 1 通过Javassist 获取UserDo的class* 2 在setName之前添加打印信息* 3 修改getName第14行输出内容System.out.println(调用了getName方法); 为System.out.println(通过avassist 修改了调用了getName方法);** author Anna.* date 2024/4/4 19:58*/
public class JavassistDemo {public static void main(String[] args) throws Exception {// 创建ClassPool对象ClassPool classPool ClassPool.getDefault();// 获取UserDoCtClass ctClass classPool.getCtClass(com.demo.demo2.UserDo);// 在setName之前添加打印信息// 获取调用setName方法CtMethod setName ctClass.getDeclaredMethod(setName, new CtClass[]{classPool.get(java.lang.String)});// 设置方法调用前打印信息 $0 表示this,$1表示第一个参数setName.insertBefore(System.out.println(\javassiist在setName前设置打印\ $1););// 获取调用getName方法CtMethod getName ctClass.getDeclaredMethod(getName);// 在getName第14行插入输出内容为System.out.println(通过avassist 修改了调用了getName方法);getName.insertAt(14, System.out.println(\通过avassist 修改了调用了getName方法\););getName.insertAfter(System.out.println(\javassiist在getName执行结束后return前设置打印\ ););// 通过反射调用新生成的方法Class? clazz ctClass.toClass();// 初始化Object o clazz.getDeclaredConstructor().newInstance();// 调用setNameMethod setName1 clazz.getMethod(setName, String.class);setName1.invoke(o, 张三);// 调用getNameMethod getName1 clazz.getMethod(getName);System.out.println(getName1.invoke(o));}
}执行结果 gitee源码 git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git