2026/9/23 11:07:57

Javassist 字节码编程入门:用 ClassPool 动态生成 HelloWorld 类的完整实战(CodeGuide 字节码编程专栏)

Javassist 字节码编程入门:用 ClassPool 动态生成 HelloWorld 类的完整实战(CodeGuide 字节码编程专栏) 文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载本文基于 CodeGuide 仓库「字节码编程」专栏的Javassist 篇一编写围绕ClassPool、CtClass、CtMethod、CtConstructor四个核心 API完整演示如何通过 Javassist 在运行时动态生成一个带有main方法和无参构造函数的类并输出HelloWorld。读完本文你将掌握 Javassist 字节码编程的基本语法骨架理解「类池 → 类 → 方法/构造器 → 输出/加载」的完整流程为后续的字节码插桩监控、热加载替换等实战场景打下基础。一、为什么需要字节码编程三大框架概览在 Java 生态中对.class字节码进行操作的常见框架主要有三个ASM、Byte-buddy、Javassist。它们都能对字节码进行操作区别在于操作方式与控制粒度ASM更偏向底层使用者需要了解 JVM 虚拟机规范以及局部变量表、操作数栈等相关知识。编写起来相对繁琐但它是性能最好、功能最强的字节码操作框架常见于 CGLIB 动态代理以及一些非入侵的探针监控场景。Byte-buddy与Javassist都提供了强大的高级 API操作使用上更容易控制。虽然与 ASM 相比性能上会略逊一筹但并非性能不好同样在大量监控场景中被广泛使用——你甚至可以在自己工程的 jar 包里搜索到它们的身影。这部分技术内容在 CRUD 日常开发中并不常用但随着自动化测试、非入侵监控的大量使用掌握字节码编程逐渐成为不少研发岗位的进阶技能。CodeGuide 仓库为此专门开设了「字节码编程」专栏从Javassist到ASM逐步成体系地组织文章本文即是其中的第一篇入门案例。同一专栏还收录了 JavaAgent 全链路监控系列 与 ASM 字节码编程系列可作为后续深入学习的素材。二、开发环境准备本文案例的开发环境如下JDK 1.8.0javassist 3.12.1.GA在 Maven 工程中引入 Javassist 依赖dependency groupIdjavassist/groupId artifactIdjavassist/artifactId version3.12.1.GA/version typejar/type /dependency说明以上依赖坐标与版本号以仓库专栏文档为准适用于 JDK 1.8 环境。若你在更高版本 JDK 或 Spring Boot 工程中使用可自行升级到兼容的 Javassist 版本但 API 用法基本保持一致。三、案例目标用字节码生成一个 HelloWorld 类抛开实现过程不谈本案例的目标非常直观使用javassist输出一行HelloWorld。等价于用普通 Java 编写出下面这个类public class HelloWorld { public static void main(String[] args) { System.out.println(javassist hi helloworld by 小傅哥(bugstack.cn)); } public HelloWorld() { } }接下来我们要做的就是用 Javassist 的字节码编程技术在运行时动态拼装出这样一个类而不是手写这段 Java 源码。四、技术实现GenerateClazzMethod 完整代码输出一个 HelloWorld 本身并不复杂重点在于从这个小案例中学习 Javassist 的基本语法结构为后续内容建立基础概念。完整实现代码如下/** * 基于 Javassist 动态生成 HelloWorld 类 */ public class GenerateClazzMethod { public static void main(String[] args) throws IOException, CannotCompileException, NotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { ClassPool pool ClassPool.getDefault(); // 创建类 classname创建类路径和名称 CtClass ctClass pool.makeClass(org.itstack.demo.javassist.HelloWorld); // 添加方法 CtMethod mainMethod new CtMethod(CtClass.voidType, main, new CtClass[]{pool.get(String[].class.getName())}, ctClass); mainMethod.setModifiers(Modifier.PUBLIC Modifier.STATIC); mainMethod.setBody({System.out.println(\javassist hi helloworld by 小傅哥(bugstack.cn)\);}); ctClass.addMethod(mainMethod); // 创建无参数构造方法 CtConstructor ctConstructor new CtConstructor(new CtClass[]{}, ctClass); ctConstructor.setBody({}); ctClass.addConstructor(ctConstructor); // 输出类内容 ctClass.writeFile(); // 测试调用 Class clazz ctClass.toClass(); Object obj clazz.newInstance(); Method main clazz.getDeclaredMethod(main, String[].class); main.invoke(obj, (Object)new String[1]); } }这段代码可以分为六块内容每一块都对应 Javassist 的一个核心 API 概念创建 ClassPoolClassPool.getDefault()获取默认的类池它是一个基于 HashMap 实现的CtClass对象容器负责管理所有被 Javassist 操作的类对象并维护类的搜索路径。使用 CtClass 创建类信息pool.makeClass(org.itstack.demo.javassist.HelloWorld)指定类的全限定路径与名称返回一个CtClass对象后续所有针对该类的操作加方法、加构造器、输出字节码都围绕它展开。给类添加方法通过CtMethod构造器依次指定方法的返回类型CtClass.voidType、方法名称main、入参类型数组new CtClass[]{pool.get(String[].class.getName())}即String[]以及所属类ctClass。再用setModifiers(Modifier.PUBLIC Modifier.STATIC)设置访问修饰符——这里用加号组合的方式同时声明public与static最后用setBody({...})写入方法体内容通过addMethod挂载到类上。创建无参构造函数CtConstructor的入参类型数组为空方法体为{}。每一个 Java 类在编译后都会生成这样一个默认构造函数因此动态生成的类也需要显式补齐。输出类内容ctClass.writeFile()将生成好的类字节码输出到工程目录下可以直观看到 Javassist 生成出来的.class文件内容。反射调用验证先通过ctClass.toClass()把动态类加载进 JVM再用newInstance()实例化最后通过反射获取main方法并invoke调用验证输出结果。五、测试结果执行程序后工程文件夹下会多出 Javassist 动态生成的类文件同时控制台输出测试结果javassist hi helloworld by 小傅哥(bugstack.cn) Process finished with exit code 0至此一个完整的Javassist 动态生成类并运行的闭环已经打通定义类 → 添加方法 → 添加构造器 → 输出字节码 → 加载到 JVM → 反射调用。六、Javassist 核心能力纵深从 HelloWorld 走向实战本篇 HelloWorld 只是 Javassist 的敲门砖。CodeGuide 仓库中的 Javassist 篇二、篇三、篇四、篇五 在此基础上不断深化这里梳理一下从本案例延伸出去的几个关键知识点1. 属性字段与$1/$2入参引用篇二在实际的字节码编程中除了方法还需要创建字段。使用CtField可以定义属性并通过Modifier.PRIVATE Modifier.STATIC Modifier.FINAL这类组合方式控制访问级别例如CtField ctField new CtField(CtClass.doubleType, π, ctClass); ctField.setModifiers(Modifier.PRIVATE Modifier.STATIC Modifier.FINAL); ctClass.addField(ctField, 3.14);在方法体中引用入参时Javassist 使用$1、$2……这样的占位符按位置取值$0代表this。同时要特别留意Javassist 不会进行类型的自动装箱和拆箱需要显式处理。例如方法返回Double对象类型时方法体内需要手动编写Double.valueOf($1 $2)这样的转换否则生成的类在执行时会报类型错误。基本类型入参可直接使用CtClass.doubleType、CtClass.intType等而对象类型入参则需通过pool.get(Double.class.getName())获取。2. 运行时热加载替换篇三利用javassist.tools.HotSwapper可以在程序运行期间动态重写某个正在执行的方法。其前置条件是启用 JPDAJava 平台调试器体系结构即启动参数中加入-agentlib:jdwptransportdt_socket,servery,suspendn,address8000随后通过pool.get(ApiTest.class.getName())获取类、getDeclaredMethod获取方法、setBody重写方法体最后用hs.reload(ApiTest.class.getName(), ctClass.toBytecode())完成热插拔。这种能力常见于热部署、模型包升级等场景。3. 字节码插桩监控篇四插桩技术常与JavaAgent结合用于系统非入侵监控可以采集方法的执行耗时、入参出参与异常信息。围绕本案例的 API 可以延伸出用ctMethod.addLocalVariable(startNanos, CtClass.longType)声明局部变量、insertBefore在方法前插入计时逻辑、insertAfter在方法后调用外部监控方法$_代表返回值、addCatch为方法整体包裹 TryCatch$e代表异常对象。此外通过MethodInfo、CodeAttribute、LocalVariableAttribute等可以读取方法的描述符、入参名称与类型判断静态方法时需通过AccessFlag.STATIC与访问标志做与运算因为静态方法的第一个参数是this会影响参数名称的获取。4. 字节码指令级控制篇五Javassist 不仅提供高级 API还提供了低级 API 直接控制字节码指令。通过MethodInfo.getCodeAttribute()配合CodeIterator可以遍历方法指令配合Mnemonic.OPCODE输出指令码通过Bytecode对象可以追加指令例如addGetstatic获取静态域压入栈顶、addInvokevirtual调用实例方法、addReturn返回 double 结果、addDconst将 double 型 0 推送至栈顶最后用methodInfo.setCodeAttribute(bytecode.toCodeAttribute())替换方法体。这一层能力可用于更精细的字节码改造例如修改方法返回值、生成带自定义注解的类与方法。七、总结Javassist 提供了完整且强大的 API动态生成类、方法、构造器的使用门槛较低代码结构也不难理解非常适合作为字节码编程的入门框架。本文案例覆盖了字节码编程最基础但最核心的 API 闭环ClassPool类池容器、CtClass类、CtMethod方法、CtConstructor构造器、writeFile输出字节码与toClass加载到 JVM。从源码结构看这正是后续所有 Javassist 实战——属性字段、热加载、插桩监控、指令级控制——共同依赖的地基。关于框架选型Javassist 相对 ASM 封装更友好多数场景下无需关心 JVM 局部变量与操作数栈的细节但若对性能与细粒度控制有更高要求则可以考虑 ASM。后续内容可在本仓库的「字节码编程」专栏中继续跟进Javassist 篇二属性与多类型出入参、篇三运行时热加载、篇四插桩监控采集出入参与异常、篇五Bytecode 指令码生成带注解的类以及 Byte-buddy 系列 与 JavaAgent 全链路监控系列。赞分享文档教程后端【免费下载链接】CodeGuide:books: 本代码库是作者小傅哥多年从事一线互联网 Java 开发的学习历程技术汇总旨在为大家提供一个清晰详细的学习教程侧重点更倾向编写Java核心内容。如果本仓库能为您提供帮助请给予支持(关注、点赞、分享)项目地址https://gitcode.com/gh_mirrors/code/CodeGuide点击查看免费下载相关推荐终极指南揭秘Java字节码编程ASM与Javassist实战技巧终极指南揭秘Java字节码编程ASM与Javassist实战技巧 Java字节码编程是高级Java开发者必须掌握的核心技能之一而ASM和Javassist正文档教程后端字节码编程与性能监控ASM、Javassist、ByteBuddy字节码编程与性能监控ASM、Javassist、ByteBuddy 本文深入探讨了Java字节码编程领域的三大主流框架ASM、Javassist和ByteB文档教程后端ExplorerPatcherWindows 11 换回 Win10 界面的完整工具3 步装好ExplorerPatcherWindows 11 换回 Win10 界面的完整工具3 步装好 刚升级到 Windows 11任务栏强制居中、开始菜单整个桌面应用系统编程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考