本博客主要介绍通过 Javassist、ASM 操作 Java 字节码。

Class 文件是什么

通常对于用 idea 的同学来说,class 文件是直接可以查看的,可以看到像 java 那样的代码。其实 class 文件是一种字节码文件,我们平时在 idea 所看到的,是 idea 自动反编译后的结果。如果把 class 文件用 sublime 打开,就会看到许多字节码,而不是 Java 代码了。像这样:

cafe babe 0000 0034 0017 0100 1163 6e2f

6863 6873 7475 6469 6f2f 5573 6572 0700

0101 0010 6a61 7661 2f6c 616e 672f 4f62

6a65 6374 0700 0301 0004 6e61 6d65 0100

......

Class文件是一组以 8 位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑排列在 Class 文件中,中间无任何分隔符。

我们这里所说的操作 Java 字节码,就是操作修改 class 文件内容。

Why

同学们可能会有这样一个疑问,为什么要操作 Java 字节码,直接改 java 文件不是很好吗?

很多情况下是无法操作的 java 文件的,或者使用修改字节码的方式更方便:

在第三方依赖中加入一些检测数据

AOP 操作,例如 Android 自动埋点统计

Spring 框架的 AOP 操作使用 ASM 操作 Java 字节码

总的来说,可以更方便开发,也同时了解一些底层的原理。

Javassist

Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru Chiba(千叶 滋)所创建的。它已加入了开放源代码 JBoss 应用服务器项目,通过使用Javassist对字节码操作为 JBoss 实现动态”AOP”框架。

导包

compile group: ‘org.javassist‘, name: ‘javassist‘, version: ‘3.23.1-GA‘

类搜索路径版本号可能不是最新的,想要最新的话查找 Maven 仓库获取最新的版本号即可。

通过 ClassPool.getDefault() 获取的 ClassPool 使用 JVM 的类搜索路径。如果程序运行在 JBoss 或者 Tomcat 等 Web 服务器上,ClassPool 可能无法找到用户的类,因为 Web 服务器使用多个类加载器作为系统类加载器。在这种情况下,ClassPool 必须添加额外的类搜索路径。

下面的例子中,pool 代表一个 ClassPool 对象:

pool.insertClassPath(new ClassClassPath(this.getClass()));

上面的语句将 this 指向的类添加到 pool 的类加载路径中。你可以使用任意 Class 对象来代替 this.getClass(),从而将 Class 对象添加到类加载路径中。传参支持 ClassPath、URLClassPath、ByteArrayClassPath 类型。

编辑

// 创建 User 类

CtClass ctClass = classPool.makeClass("cn.hchstudio.User");

// 获取 String 类

CtClass CtString = classPool.get("java.lang.String");

通过 makeClass 和 get 方法可以分别创建、获取 CtClass,进而操作类。

上面的语句是创建一个变量,new CtField 中分别传入类型、名称、ctClass。setModifiers 设置变量修饰符;addField 表示把变量加入到这个类中。

CtField name = new CtField(CtString, "name", ctClass);

name.setModifiers(Modifier.PRIVATE);

ctClass.addField(name);

对于已存在的方法,可以使用 insertBefore、insertAfter 方法插入到方法函数之后或之后。Javassist 有一个简单除暴的新增方法方式,就是直接把要写的 java 代码变为字符串,之后 Javassist 便可自动完成代码校验,转为字节码的过程。

ctMethod.insertBefore("System.out.println(\"lalala\");");

ctMethod.insertAfter("System.out.println(\"lalala\");");

一个栗子

举一个栗子,这里通过 Javassist 生成一个 User 类,其中包括 name、sex 属性,并有其 set、get 方法。并且输出到 ./out/production/classes 目录下。

ClassPool classPool = ClassPool.getDefault();

try {

CtClass ctClass = classPool.makeClass("cn.hchstudio.User");

CtClass CtString = classPool.get("java.lang.String");

CtField name = new CtField(CtString, "name", ctClass);

name.setModifiers(Modifier.PRIVATE);

ctClass.addField(name);

CtField sex = new CtField(CtString, "sex", ctClass);

sex.setModifiers(Modifier.PRIVATE);

ctClass.addField(sex);

CtMethod setName = new CtMethod(CtClass.voidType, "setName",

new CtClass[]{CtString}, ctClass);

setName.setModifiers(Modifier.PUBLIC);

setName.setBody("name = $1;");

ctClass.addMethod(setName);

CtMethod getName = new CtMethod(CtString, "getName",

new CtClass[]{}, ctClass);

getName.setModifiers(Modifier.PUBLIC);

getName.setBody("return name;");

ctClass.addMethod(getName);

CtMethod setSex = CtMethod.make("public void setSex(java.lang.String sex){" +

"this.sex = sex;" +

"}", ctClass);

ctClass.addMethod(setSex);

CtMethod getSex = new CtMethod(CtString, "getSex",

new CtClass[]{}, ctClass);

getSex.setModifiers(Modifier.PUBLIC);

getSex.setBody("return sex;");

ctClass.addMethod(getSex);

ctClass.writeFile("./out/production/classes");

} catch (Exception e) {

System.out.println(e.toString());

e.printStackTrace();

}

ASM

ASM 也是一个操作 Java 字节码的框架,相比于 Javassist,它更加底层、轻量级、速度也快,不过在编写代码的时候可能容易出错,它需要我们直接写 Java 字节码。

Java jdk 自带了 ASM 的依赖,在 rt.jar!/jdk/internal/org/objectweb/asm 下。

Android 环境下则需要自己导入依赖,因为 Android 去掉了 rt.jar!/jdk 包。

编辑

ASM 编辑代码则比较复杂,需要对汇编有一定了解的同学才可以。

通常的方式是我们需要用 java 写出一个想要自动生成的类,然后查看他的 class 字节码

mv = cw.visitMethod(ACC_PUBLIC, "setName", "(Ljava/lang/String;)V", null, null);

mv.visitCode();

mv.visitVarInsn(ALOAD, 0);

mv.visitVarInsn(ALOAD, 1);

mv.visitFieldInsn(PUTFIELD, "cn/hchstudio/User", "name", "Ljava/lang/String;");

mv.visitInsn(RETURN);

mv.visitMaxs(2, 2);

mv.visitEnd();

这里改出一段示例代码,意思为新建一个 setName 方法,并给 name 属性赋值。

java操作字节码_操作Java字节码相关推荐

  1. java项目----教务管理系统_基于Java的教务管理系统

    java项目----教务管理系统_基于Java的教务管理系统 2022-04-22 18:18·java基础 最近为客户开发了一套学校用教务管理系统,主要实现学生.课程.老师.选课等相关的信息化管理功 ...

  2. java编译后生成字节码_请问java源文件编译后怎么生成字节码文件?

    比如,有的java源程序生成一个字节码文件,带有内部类的生成两个.可是有一种情况怎么回事呢?importjava.awt.*;importjavax.swing.*;importjava.awt.ev ...

  3. java中字节码_聊聊Java的字节码

    本文为作者原创,转载请注明出处(http://www.cnblogs.com/mar-q/)by 负赑屃 巴山楚水凄凉地,二十三年弃置身. 怀旧空吟闻笛赋,到乡翻似烂柯人. 沉舟侧畔千帆过,病树前头万 ...

  4. java 对象复制 反射_利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档) ...

  5. fileoutputstream 字节乱码_吃透Java IO:字节流、字符流、缓冲流

    前言 有人曾问fastjson的作者(阿里技术专家高铁):"你开发fastjson,没得到什么好处,反而挨了骂背了锅,这种事情你为什么要做呢?" 高铁答道:"因为热爱本身 ...

  6. java 读取mysql数据库_原生Java操作mysql数据库过程解析

    这篇文章主要介绍了原生Java操作mysql数据库过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.引入数据库驱动的jar包 以通过mav ...

  7. java 中文域名转码_转换java方法

    java date String 类型相互转换 这种转换要用到java.text.SimpleDateFormat类 字符串转换成日期类型: 方法1: 也是最简单的方法 Date date=new D ...

  8. java web开源项目源码_适合Java新手的开源项目集合——在 GitHub 学编程

    作者:HelloGitHub-老荀 当今互联网份额最大的编程语言是哪一个?是 Java!这两年一直有听说 Java 要不行了.在走下坡路了.没错,Java 的确在走下坡路,未来的事情的确不好说,但是瘦 ...

  9. java后端做教育视频网站源码_【Java并发面试点】看这一篇应该是够了

    [Java并发面试点]看这一篇应该是够了 Java并发编程是Java后端.大数据开发面试必问项目之一,求职者务必掌握! Java并发面试点List 并发概念须知:进程与线程.同步与异步.并发与并行.阻 ...

  10. java qq聊天界面_【附源码】用Java写了一个类QQ界面聊天小项目,可在线聊天!...

    原标题:[附源码]用Java写了一个类QQ界面聊天小项目,可在线聊天! 目录: 1.功能实现 2.模块划分 3.使用到知识 4.部分代码实现 5.运行例图 1.功能实现 1.修改功能(密码.昵称.个性 ...

最新文章

  1. 修改科技论文的6项注意
  2. 虚拟机克隆以后出现“需要整合虚拟机磁盘”的解决方法
  3. 文件读写以及数据处理
  4. Android--查找程序根目录下所有文件/Java IO操作
  5. CentOS7+CDH5.14.0安装全流程记录,图文详解全程实测-8CDH5安装和集群配置
  6. a5d2 phy驱动
  7. Weblogic的管理服务器与受管服务器
  8. Python 爬取近十万条程序员招聘数据,告诉你哪类人才和技能最受热捧! | 原力计划...
  9. opencv cv.waitKey(60) 0xff 含义和作用
  10. 42表盘直径是从哪测量_万用表测量电容容量的方
  11. JMeter压力测试和性能优化
  12. MSN:常见故障“步步通”(转)
  13. 数字基带调制解调matlab仿真,我的基于MATLAB仿真的数字调制与解调设计
  14. 【安卓】2.修改app名、图标、主题风格(保姆级图文+附示例+api例程)
  15. 豆瓣高分电影爬取学习心得
  16. ZBrush:笔刷基础
  17. SpringSecurity如何处理logout注销操作
  18. 关于STM32的BSRR(端口位设置/清除寄存器) 和 BRR(端口位清除寄存器) 的理解(初学32)
  19. Android Studio的Logcat/Run/Terminal/Build等窗口没有了怎么调出
  20. spss常态检验_【单选题】SPSS 软件中进行数据描述、 t 检验等分析的菜单是( )。 A. 文件 B. 数据 C. 转换 D. 分析...

热门文章

  1. python-摩尔斯电码查询器
  2. .NET常用类库--苏飞合集
  3. UISegmentedControl触发事件的错误
  4. linux下iSCSI的配置
  5. HDU 3339 In Action(最短路+背包)题解
  6. BZOJ4598 [Sdoi2016]模式字符串 【点分治 + hash】
  7. 蓝桥杯 公约数公倍数
  8. Android——ViewPager多页面滑动切换以及动画效果
  9. linux sshd 开机自启动
  10. 开发组2007年3月开发计划