Java-ASM框架学习-修改类的字节码
Tips: ASM使用访问者模式,学会访问者模式再看ASM更加清晰
ClassReader
用于读取字节码,父类是Object
主要作用:
- 分析字节码里各部分内容,如版本、字段等等
- 配合其他Visitor使用
主要使用的方法
public void accept(ClassVisitor classVisitor, int parsingOptions) {
this.accept(classVisitor, new Attribute[0], parsingOptions);
}
// 第一个参数是访问者,第二个参数用于跳过读取字节码的一些信息,常用ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES,跳过没必要的调试和帧信息以缩小大小
如何修改已存在的字节码
通过继承ClassVisitor,重写visitxxx方法,在方法中对访问到的数据进行操作,然后传给下一个ClassVisitor的子类处理(如果有的话)。经过一个或多个ClassVisitor的访问链处理后,传到ClassWriter手里,由ClassWriter生成最终的字节码结果

ClassVisitor方法通过构造函数可以传递下一个Visitor进去,如同链表一样,一个个的形成访问链,最后链接到ClassWriter这个特殊的ClassVisitor里去形成结果
实例
被修改的类
package example;
public class TestClass01 {
public int a;
public int b;
public TestClass01() {
System.out.println("init!!");
}
}
ASM代码
package example.modify;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import java.io.IOException;
import example.modify.clsvisitor.*;
import org.objectweb.asm.Opcodes;
import utils.FileUtils;
public class Test01 {
public static void main(String[] args) throws IOException {
String path = FileUtils.getFilePath("example/sample/TestClass01.class");
FileUtils.writeBytes(path, modifyClass());
}
public static byte[] modifyClass() {
ClassReader cr = null;
try {
cr = new ClassReader("example.TestClass01");
} catch (IOException e) {
e.printStackTrace();
}
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
ClassVisitor cv = new TestClass01Visitor(Opcodes.ASM9, cw);
cr.accept(cv, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return cw.toByteArray();
}
}
package example.modify.clsvisitor;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;
public class TestClass01Visitor extends ClassVisitor {
private String addFieldN = "content";
private boolean flag1 = true;
private String addStaticFieldN = "myID";
private int addStaticFieldV = 100;
private boolean flag2 = true;
private String delFieldN = "b";
public TestClass01Visitor(int api, ClassVisitor classVisitor) {
super(api, classVisitor);
}
/**
* 把java版本改成1.6 全限定名改成sample包下,避免两个同样的类冲突
* @param version
* @param access
* @param name
* @param signature
* @param superName
* @param interfaces
*/
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
super.visit(Opcodes.V1_6, access, "example/sample/TestClass01", signature, superName, interfaces);
}
/**
* 添加两个成员删一个成员
* @param access
* @param name
* @param descriptor
* @param signature
* @param value
* @return
*/
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
if (name.equals(delFieldN)) return null;
if (name.equals(addFieldN)) flag1 = false; // 存在就不添加
if (name.equals(addStaticFieldN)) flag2 = false;
return super.visitField(access, name, descriptor, signature, value);
}
@Override
public void visitEnd() {
super.visitField(
Opcodes.ACC_PUBLIC,
this.addFieldN,
"Ljava/lang/String;",
null,
""
);
super.visitField(
Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL,
this.addStaticFieldN,
"I",
null,
this.addStaticFieldV
);
super.visitEnd();
}
}
生成的字节码结果(idea反编译后)

Java-ASM框架学习-修改类的字节码的更多相关文章
- 从Java进程里dump出类的字节码文件
想要查看一些被增强过的类的字节码,或者一些AOP框架的生成类,就需要dump出运行时的Java进程里的字节码. 从运行的java进程里dump出运行中的类的class文件的方法: 用agent att ...
- 浅谈Java反射机制 之 获取类的字节码文件 Class.forName("全路径名") 、getClass()、class
另一个篇:获取 类 的 方法 和 属性(包括构造函数) 先贴上Java反射机制的概念: AVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它 ...
- Java-ASM框架学习-从零构建类的字节码
Tips: ASM使用访问者模式,学会访问者模式再看ASM更加清晰 什么是ASM ASM是一个操作Java字节码的类库 学习这个类库之前,希望大家对Java 基本IO和字节码有一定的了解. 高版本的A ...
- Java集合框架(常用类) JCF
Java集合框架(常用类) JCF 为了实现某一目的或功能而预先设计好一系列封装好的具有继承关系或实现关系类的接口: 集合的由来: 特点:元素类型可以不同,集合长度可变,空间不固定: 管理集合类和接口 ...
- Java最重要的21个技术点和知识点之JAVA集合框架、异常类、IO
(三)Java最重要的21个技术点和知识点之JAVA集合框架.异常类.IO 写这篇文章的目的是想总结一下自己这么多年JAVA培训的一些心得体会,主要是和一些java基础知识点相关的,所以也希望能分享 ...
- Java虚拟机JVM学习07 类的卸载机制
Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...
- Java虚拟机JVM学习04 类的初始化
Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...
- Java虚拟机JVM学习02 类的加载概述
Java虚拟机JVM学习02 类的加载概述 类的加载 类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对 ...
- JVM学习笔记——类加载和字节码技术篇
JVM学习笔记--类加载和字节码技术篇 在本系列内容中我们会对JVM做一个系统的学习,本片将会介绍JVM的类加载和字节码技术部分 我们会分为以下几部分进行介绍: 类文件结构 字节码指令 编译期处理 类 ...
随机推荐
- NOI 2021 部分题目题解
最近几天复盘了一下NOI 2021,愈发发觉自己的愚蠢,可惜D2T3仍是不会,于是只写前面的题解 Day1 T1 可以发现,每次相当于将 \(x\to y\) 染上一种全新颜色,然后一条边是重边当且仅 ...
- SpringBoot配置文件application
配置文件 SpringBoot使用一个全局的配置文件 , 配置文件名称是固定的,有两种文件格式: application.properties 语法结构 :key=value application. ...
- Mysql双主双从高可用集群的搭建且与MyCat进行整合
1.概述 老话说的好:瞻前顾后.患得患失只会让我们失败,下定决心,干就完了. 言归正传,之前我们聊了Mysql的一主一从读写分离集群的搭建,虽然一主一从或一主多从集群解决了并发读的问题,但由于主节点只 ...
- javascript运算符和表达式
1.表达式的概念 由运算符连接操作组成的式子,不管式子有多长,最终都是一个值. 2.算术运算符 加+ 减- 乘* 除/ 取模% 负数- 自增++ 自减-- 3.比较运算符 等于== 严格等于=== ...
- 【UE4 C++】抛物线路径、发射轨道相关
基于UGameplayStatics Blueprint_PredictProjectilePath_ByObjectType 根据 Object Type,算出抛物线的点集合和检测结果 static ...
- 寻找写代码感觉(八)之SpringBoot过滤器的使用
一.什么是过滤器? 过滤器是对数据进行过滤,预处理过程,当我们访问网站时,有时候会发布一些敏感信息,发完以后有的会用*替代,还有就是登陆权限控制等,一个资源,没有经过授权,肯定是不能让用户随便访问的, ...
- Beta阶段初始任务分配
项目 内容 这个作业属于哪个课程 2021春季软件工程(罗杰 任健) 这个作业的要求在哪里 团队项目-计划-Beta阶段说明书 一.Beta阶段总体规划 根据用户反馈与测试结果修复alpha版本的bu ...
- Noip模拟45 2021.8.21
一定别删大括号,检查是;还是, ceil函数里面要写double,否则根本没用!!!!!!! T1 打表 正解:打表 考场上很难真正把柿子理解着推出来 况且想要理解题意就很难,比如我就理解错了 半猜着 ...
- 用python检查矩阵的计算
鉴于最近复习线性代数计算量较大,且1800答案常常忽略一些逆阵.行列式的计算答案,故用Python写出矩阵的简单计算程序,便于检查出错的步骤. 1.行列式 可自行更改阶数 from numpy imp ...
- WPF进阶技巧和实战08-依赖属性与绑定03
数据提供者 在大多数的代码中,都是通过设置元素的DataContext属性或者列表控件的ItemsSource属性,从而提供顶级的数据源.当数据对象是通过另一个类构造时,可以有其他选择. 一种是作为窗 ...