JVM Class字节码之三-使用BCEL改变类属性
使用BCEL动态改变Class内容
之前对Class文件中的常量池,Method的字节码指令进行了说明。
JVM Class详解之一
JVM Class详解之二 Method字节码指令
现在我们开始实际动手,使用BCEL改变字节码指令,对Class文件进行功能扩充。
先介绍下BCEL全程Apache Byte Code Engineering Library,BCEL 每项内容操作在JVM汇编语言的级别
HelloWorld搞起
这个case我们需要给Programmer类做功能扩展,Programmer 职责进行了变化,除了要Coding以外,在每次Coding之前需要先做Plan,所以需要在do Coding信息输出之前输出 "doBcelPlan..." 信息。
Demo
public class Programmer implements Person {@Overridepublic void doCoding() {System.out.println("do Coding...");}}
期望效果
@Overridepublic void doCoding() {doPlan();System.out.println("do Coding...");}private void doPlan() {System.out.println("do Plan...");}
需要做什么
针对我们的期望结果我们需要做以下三点
- 增加一个doBcelPlan方法
- 在doCoding方法中调用doBcelPlan方法
- 在常量池中加入方法的声明,常量等其它使用到的变量和方法。
工程先引入BCEL的依赖Pom中追加即可
<dependency><groupId>asm</groupId><artifactId>asm</artifactId><version>3.1</version></dependency><dependency><groupId>asm</groupId><artifactId>asm-tree</artifactId><version>3.1</version></dependency>
1. 先使用BCEL 加载需要编辑的Class
JavaClass clazz = Repository.lookupClass(Programmer.class);ClassGen classGen = new ClassGen(clazz);ConstantPoolGen cPoolGen = classGen.getConstantPool(); // 常量池信息
2. 在常量池中增加一个MethodRef doBcelPlan
int methodIndex = cPoolGen.addMethodref("byteCode.decorator.Programmer", "doBcelPlan", "()V"); // 在常量池中增加一个方法的声明返回methodIndex为声明在常量池中的位置索引
第一个参数的去路径类名
第二个参数是方法名称
第三个方法返回类型 ()V 是void类型
方法返回类型描述参考
3. 在常量池中增加一个String类型的Filed
因为有System.out.println("doBcelPlan")语句
doBcelPlan中的System.out 变量和println方法再doCoding中已经使用所有已经在常量池中了
int stringIndex = cPoolGen.addString("doBcelPlan...");// 在常量池中增加一个Field的声明返回stringIndex为声明在常量池中的位置索引
注意这里需要记录追加方法和Filed的index后面需要使用。
4. 然后创建doBcelPlan方法的实体的字节码指令
调用System.out变量和println方法 具体的字节码指令参数 上一节内容有说明 参考上一节文档 JVM Class详解之二 Method字节码指令
InstructionList instructionDoPlan = new InstructionList(); // 字节码指令信息
instructionDoPlan.append(new GETSTATIC(17)); // 获取System.out常量
instructionDoPlan.append(new LDC(stringIndex)); // 获取String Field信息
instructionDoPlan.append(new INVOKEVIRTUAL(25)); // 调用Println方法
instructionDoPlan.append(new RETURN()); // return 结果
其中17,25都是常量池的引用参见下图,将原先的Programmer类编译后使用javap -versobse XXX.class 可以查看常量池信息。
stringIndex 是引用第三步追加常量池String Field soBcelPlan
5. 生成doBcelPlan方法
MethodGen doPlanMethodGen = new MethodGen(1, Type.VOID, Type.NO_ARGS, null, "doBcelPlan",
classGen.getClassName(), instructionDoPlan, cPoolGen);
classGen.addMethod(doPlanMethodGen.getMethod());
方法的声明并追加到classGen中。
这样doBcelPlan方法就追加成功了。接下来我们需要找到doCoding方法,在方法中追加doBcelPlan的调用。
6. 找到并修正doCoding方法
Method[] methods = classGen.getMethods();for (Method method : methods) {String methodName = method.getName();if ("doCoding".equals(methodName)) {MethodGen methodGen = new MethodGen(method, clazz.getClassName(), cPoolGen);InstructionList instructionList = methodGen.getInstructionList();InstructionHandle[] handles = instructionList.getInstructionHandles();InstructionHandle from = handles[0];InstructionHandle aload = instructionList.append(from, new ALOAD(0));instructionList.append(aload, new INVOKESPECIAL(methodIndex));classGen.replaceMethod(method, methodGen.getMethod());}}
InstructionList 是当前方法中的字节码指令,我们append了两个指令ALOAD和INVOKESPECIAL。实现doBcelPlan的调用。
7. 将编辑后的Class输出
JavaClass target = classGen.getJavaClass();target.dump("D:\\AliDrive\\bytecode\\bcel\\Programmer.class");
将修改后的字节码输出来看下,使用JD打开OK
可以看到经过编辑后的Class文件输出结果同我们预期的是一样的
Done!
from: https://yq.aliyun.com/articles/7243?spm=5176.100239.blogcont7241.37.db8GKF
JVM Class字节码之三-使用BCEL改变类属性相关推荐
- 【JVM】字节码与ASM字节码增强、Instrument实现类的动态重加载
目录 字节码与ASM字节码增强 什么是字节码? 字节码结构 操作数栈与字节码 字节码增强 ASM 运行时类加载 Instrument JPDA与JVMTI instrument实现热加载的过程 字节码 ...
- JVM学习-字节码指令
目录 1.入门 2 javap 工具 3 图解方法执行流程 3.1.原始 java 代码 3.2.编译后的字节码文件 3.3.常量池载入运行时常量池 3.4.方法字节码载入方法区 3.5.main 线 ...
- JVM与字节码——2进制流字节码解析
为什么80%的码农都做不了架构师?>>> 字节码解析 结构 本位将详细介绍字节码的2进制结构和JVM解析2进制流的规范.规范对字节码有非常严格的结构要求,其结构可以用一个JSO ...
- Java字节码介绍及动态修改类
前言 对于Java字节码,它是在Java类的编译过程产生的,即由.java源文件到.class二进制字节码文件的过程.而Java类的加载又是通过类的名字获取二进制字节流,然后在内存中将字节流生成类对象 ...
- python修改类的属性值_python 四种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,直接修改类属性的值...
三种方法修改类变量,实例对象调用类方法改变类属性的值,类对象调用类方法改变类属性的值,调用实例方法改变类属性的值,类名就是类对象,city就是类变量, #coding=utf-8 class empl ...
- 第六章JVM虚拟机字节码执行引擎——类文件和类加载之前必看
文章目录 虚拟机字节码执行引擎 运行时栈帧结构 局部变量表(Local Variables) 操作数栈 动态链接(Dynamic Linking) 方法返回地址 附加信息 方法调用 解析 分派 虚方法 ...
- 深入理解JVM一字节码执行
文章目录 前言 栈帧结构 每个方法调用开始到退出,都对应着一个"栈帧"进站与出站. 运行时栈帧 栈帧-局部变量表 栈帧-操作数栈(Operand Stack) 栈帧-动态连接 栈帧 ...
- jvm理论-字节码指令
Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成. 基本数据类型 1.除了l ...
- JVM(1)——字节码
1.JVM基础 1.1.JDK,JRE,JVM关系 JDK JDK(Java Development Kit) 是用于开发 Java 应用程序的软件开发工具集合,包括 了 Java 运行时的环境(JR ...
最新文章
- 哈工大推智能荐股,能让你稳赚不赔吗?
- python读取txt文件内容-python如何获取txt文本文件中的内容
- 《人月神话》阅读笔记2
- Lambda架构概述
- 一般将来时语法课教案_速看,如何在考场写出一篇脱颖而出的教案
- 命令行导出和导入数据库 How to export and import MySQL database using command line Interface...
- npm和package.json那些不为常人所知的小秘密
- 数据结构 周末舞会(循环队列解法)
- python识别图片中数字_使用Python程序识别图像中的数字
- 早起的奇迹:那些能够在早晨8:00前改变人生的秘密
- 1097: 蛇行矩阵
- OSError: cannot open resource
- 业务流程管理(BPM)系统的九大必备特点
- MySQl安装与学习,内附SQlyog
- xms和xmx为什么要相同_为什么结婚蚕丝被,一定要有双宫茧子母被?
- 〖Python 数据库开发实战 - MySQL篇⑨〗- 什么是 SQL 语言、如何创建数据逻辑库及如何创建数据表
- 水表读数图解_水表读数怎么正确看 水表怎么读?
- linux中单引号、双引号
- 汤因比的《历史研究》所感之一
- 行为研究:用户行为背后的意义和4点价值