网站首页 > java教程 正文
javassist全称(Java Programming Assistant),是一款比JDK内置库操作字节码更方便的代码库。为了方便实验,先引入它的依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
什么是字节码呢?字节码就是一套可以被JVM处理的指令集,JVM将字节码指令转换为机器级汇编指令。举例如下:
创建一个User类,并用javac编译后得到User.class
public class User {
private String name;
private int age;
public void baseinfo(String name, int age){
this.name = name;
this.age = age;
}
}
然后 javap -c User.class 输出下面的字节码(java version "1.8.0_181")
public class bluesky.javassist.User {
public bluesky.javassist.User();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void baseinfo(java.lang.String, int);
Code:
0: aload_0
1: aload_1
2: putfield #2 // Field name:Ljava/lang/String;
5: aload_0
6: iload_2
7: putfield #3 // Field age:I
10: return
}
aload_0指令将this指针入栈,aload_1将name变量入栈,putfield是实例字段访问指令,此处就是设置name字段。javassist可以帮助我们非常方便的操作这些字节码。
使用javassist生成一个类:
// 创建一个ClassFile对象
ClassFile cf = new ClassFile(false, "bluesky.javassist.JavassistGeneratedClass", null);
// 设置JavassistGeneratedClass实现Cloneable接口
cf.setInterfaces(new String[] {"java.lang.Cloneable"});
// 添加id属性
FieldInfo f = new FieldInfo(cf.getConstPool(), "id", "I");
// 属性的修饰符
f.setAccessFlags(AccessFlag.PUBLIC);
cf.addField(f);
ClassPool classPool = ClassPool.getDefault();
// 生成JavassistGeneratedClass类并获取它的所有属性
Field[] fields = classPool.makeClass(cf).toClass().getFields();
// 断言是否存在id属性
assertEquals(fields[0].getName(), "id");
获取方法baseinfo的指令:
ClassPool cp = ClassPool.getDefault();
ClassFile cf = cp.get("bluesky.javassist.User")
.getClassFile();
MethodInfo minfo = cf.getMethod("baseinfo");
CodeAttribute ca = minfo.getCodeAttribute();
CodeIterator ci = ca.iterator();
List<String> operations = new LinkedList<>();
while (ci.hasNext()) {
int index = ci.next();
int op = ci.byteAt(index);
operations.add(Mnemonic.OPCODE[op]);
}
assertEquals(operations,
Arrays.asList(
"aload_0",
"aload_1",
"putfield",
"aload_0",
"iload_2",
"putfield",
"return"));
添加构造方法:
ClassFile cf = ClassPool.getDefault().get("bluesky.javassist.User").getClassFile();
Bytecode code = new Bytecode(cf.getConstPool());
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
在方法指定为止插入自己需要的逻辑:
ClassPool classPool = ClassPool.getDefault();
CtClass ctClass = classPool.get("bluesky.javassist.User");
CtMethod declaredMethod = ctClass.getDeclaredMethod("baseinfo");
declaredMethod.insertBefore("System.out.println(\"方法执行的第一行\")");
declaredMethod.insertAfter("System.out.println(\"方法return前\")");
User instance = (User) ctClass.toClass().newInstance();
instance.baseinfo("hello", 1);
通常可以使用字节码技术实现动态代理、热加载、debug、结合agent实现应用指标监控等。
猜你喜欢
- 2024-09-19 Java8 的这个特性,用起来真的很爽
- 2024-09-19 Linux Centos7系统下关于jdk1.8的安装和配置讲解
- 2024-09-19 java8里的排序,1行代码搞定以前20行的事,程序员又可以早下班了
- 2024-09-19 Java入门第一天(java入门到)
- 2024-09-19 Java14~java8~Java1各大版本中令人激动的特性
- 2024-09-19 Linux在线安装JDK1.8(linux在线安装python3)
- 2024-09-19 程序员必须掌握的JDK1.8的新特性(一)
- 2024-09-19 JDK1.8 Lambda表达式详解和使用(在jdk8中,lambda表达式支持的引用类型主要有)
- 2024-09-19 五、安装配置JDK1.8(jdk1.8.0_151安装和配置)
- 2024-09-19 JDK 8 的安装与配置(jdk8安装教程win10详细)
你 发表评论:
欢迎- 最近发表
-
- class版本不兼容错误原因分析(class更新)
- 甲骨文Oracle公司为Java的最新LTS版本做出改进
- 「版本发布」Minecraft Java开发版 1.19.4-pre1 发布
- java svn版本管理工具(svn软件版本管理)
- 我的世界1.8.10钻石在第几层(我的世界1.7.2钻石在哪层)
- Java开发高手必备:在电脑上轻松切换多个JDK版本
- 2022 年 Java 开发报告:Java 8 八年不到,开发者都在用什么?
- 开发java项目,选择哪个版本的JDK比较合适?
- Java版本选型终极指南:8 vs 17 vs 21特性对决!大龄程序员踩坑总结
- POI Excel导入(poi excel导入附件)
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)