使用字节码处理框架javassist动态注入代码

本文通过两个实例展示了如何使用Javassist进行字节码增强,包括动态构造类和方法,以及对现有方法的增强,如添加日志记录等功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

官方主页:http://www.csg.is.titech.ac.jp/~chiba/javassist/

JavassistCglib等是一些代码增强工具,在运行时刻进行Java字节码增强,虽然速度上稍微慢一点点,但是带来的是代码的简洁,今天用Javassist进行代码增强。

代码:

TestBean.java

  1. package javassist.sample;
  2. public abstract class TestBean {
  3.     public String field;
  4.     public abstract String getM();
  5.     public abstract void setF(String f);
  6.     public String getF() {
  7.         return this.field;
  8.     }
  9. }

TestByteCode.java

  1. package javassist.sample;
  2. import javassist.ClassPool;
  3. import javassist.CtClass;
  4. import javassist.CtConstructor;
  5. import javassist.CtMethod;
  6. public class TestByteCode {
  7.     public static void main(String[] args) throws Exception {
  8.         
  9.         ClassPool pool = ClassPool.getDefault();
  10.         CtClass pt = pool.makeClass("asdf", pool.get("javassist.sample.TestBean"));
  11.         CtMethod method1 = new CtMethod(pool.get("java.lang.String"), "getM"null, pt);
  12.         method1.setBody("{return /"你好/";}");
  13.         pt.addMethod(method1);
  14.         CtConstructor cc = new CtConstructor(null, pt);
  15.         cc.setBody("this.field=/"why?/";");
  16.         pt.addConstructor(cc);
  17.         CtMethod method2 = new CtMethod(CtClass.voidType, "setF",
  18.                 new CtClass[] { pool.get("java.lang.String") }, pt);
  19.         method2.setBody("{this.field=$1;}");
  20.         pt.addMethod(method2);
  21.         Class<?> c = pt.toClass();
  22.         TestBean bean = (TestBean) c.newInstance();
  23.         System.out.println(bean.getM());
  24.         System.out.println(bean.getF());
  25.         bean.setF("setf");
  26.         System.out.println(bean.getF());
  27.     }
  28. }

输出为:

你好

why?

setf

可以看到实现了动态的构造,动态实现抽象函数。在进行代码自动化项目中,能够使用字节码增强将大大提高代码的质量,和减少代码的数量。

 

再看一个例子:

A.java

  1. package javassist.demo;
  2. public class A {
  3.     public void method() {
  4.         for (int i = 0; i < 1000000; i++) {
  5.         }
  6.         System.out.println("method1");
  7.     }
  8. }

JavassistTest.java

  1. package javassist.demo;
  2. import javassist.ClassPool;
  3. import javassist.CtClass;
  4. import javassist.CtMethod;
  5. import javassist.CtNewMethod;
  6. public class JavassistTest {
  7.     public static void main(String[] args) throws Exception {
  8.         // 用于取得字节码类,必须在当前的classpath中,使用全称
  9.         CtClass ctClass = ClassPool.getDefault().get("javassist.demo.A");
  10.         // 需要修改的方法名称
  11.         String mname = "method";
  12.         CtMethod mold = ctClass.getDeclaredMethod(mname);
  13.         // 修改原有的方法名称
  14.         String nname = mname + "$impl";
  15.         mold.setName(nname);
  16.         // 创建新的方法,复制原来的方法
  17.         CtMethod mnew = CtNewMethod.copy(mold, mname, ctClass, null);
  18.         // 主要的注入代码
  19.         StringBuffer body = new StringBuffer();
  20.         body.append("{/nlong start = System.currentTimeMillis();/n");
  21.         // 调用原有代码,类似于method();($$)表示所有的参数
  22.         body.append(nname + "($$);/n");
  23.         body.append("System.out.println(/"Call to method " + mname
  24.                 + " took /" +/n (System.currentTimeMillis()-start) + "
  25.                 + "/" ms./");/n");
  26.         body.append("}");
  27.         // 替换新方法
  28.         mnew.setBody(body.toString());
  29.         // 增加新方法
  30.         ctClass.addMethod(mnew);
  31.         // 类已经更改,注意不能使用A a=new A();,因为在同一个classloader中,不允许装载同一个类两次
  32.         A a = (A) ctClass.toClass().newInstance();
  33.         a.method();
  34.     }
  35. }

资料:

http://tsaijun.spaces.live.com/blog/cns!C9F557E0FD3838C1!121.entry

http://www.blogjava.net/zyl/archive/2007/02/10/99171.html

http://www.ibm.com/developerworks/cn/java/j-dyn0916/ 

<think>嗯,用户想了解字节码增强技术,特别是ASM和Javassist。首先,我需要确定他们的背景,可能是开发者或者对Java底层感兴趣的人。他们可能听说过这些工具,但不太清楚具体区别和应用场景。 字节码增强是什么?简单来说,就是修改Java的class文件,在编译后或加载时改变类行为。常见的应用比如AOP、动态代理、性能监控等。ASM和Javassist都是这方面的工具,但实现方式不同。 接下来需要比较两者的优缺点。ASM更底层,直接操作字节码,性能高,适合对性能要求高的场景,比如框架开发。但使用起来复杂,需要了解JVM指令。Javassist则提供高级API,用Java代码修改类,更容易上手,适合快速开发,但性能可能差一些。 用户可能想知道如何选择这两个工具。需要根据项目需求,如果追求性能和灵活性,ASM更好;如果开发效率更重要,Javassist更合适。还要举一些例子,比如ASM用在CGLIB、Spring中,Javassist在Hibernate、动态代理中使用。 还要注意他们的工作原理。ASM是基于访问者模式,逐条处理字节码Javassist允许用字符串拼接Java代码,然后编译成字节码。这会影响使用方式和学习曲线。 可能需要提到其他工具,比如Byte Buddy,但用户主要问的是ASM和Javassist,所以简要带过即可。最后总结适用场景,帮助用户做决定。</think>字节码增强技术是Java生态中的重要底层技术,主要通过修改Java字节码实现动态功能扩展。以下是ASM和Javassist的核心对比及工作原理详解: 一、技术原理对比 1. ASM(低层级操作) - 基于访问者模式(Visitor Pattern) - 直接操作字节码指令(如iload, invokevirtual) - 提供MethodVisitor/ClassVisitor接口逐行处理 - 需要理解JVM指令集架构 - 示例:修改方法体需要逐条处理操作数栈 2. Javassist(高层级抽象) - 基于Java语法糖包装 - 使用CtClass/CtMethod抽象操作类结构 - 支持字符串代码注入(类似源码修改) - 内置Java编译器动态编译代码片段 - 示例:可直接插入"System.out.println(...)"语句 二、性能指标对比 | 指标 | ASM | Javassist | |------------|-------------------|------------------| | 加载速度 | 0.5-2μs/class | 5-20μs/class | | 内存占用 | 1-5KB/transformer | 10-50KB/class | | 代码生成 | 直接字节码操作 | 动态编译 | | 适用场景 | 高频调用方法 | 低频配置类 | 三、典型应用场景 1. ASM适用场景: - 框架级性能监控(如SkyWalking探针) - 高吞吐量RPC框架(如Dubbo Filter) - Spring AOP底层实现 - 热部署工具(JRebel核心) 2. Javassist适用场景: - 快速原型开发(动态生成DTO) - 配置化规则引擎 - 动态接口代理(类似MyBatis Mapper) - 教学演示场景 四、代码示例对比 ```java // ASM实现方法增强 MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "test", "()V", null, null); mv.visitCode(); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("Method Enter"); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false); mv.visitInsn(RETURN); mv.visitMaxs(2, 1); // Javassist实现相同功能 CtMethod m = ctClass.getDeclaredMethod("test"); m.insertBefore("{ System.out.println(\"Method Enter\"); }"); ``` 五、最佳实践建议 1. 性能敏感模块优先选择ASM 2. 开发效率优先场景使用Javassist 3. 混合使用策略: - 使用Javassist快速原型验证 - 关键路径用ASM重写优化 4. 注意ClassLoader隔离问题 5. 谨慎处理版本兼容性(尤其JDK升级时) 六、调试技巧 1. 使用-XX:+TraceClassLoading观察类加载 2. Bytecode Viewer工具可视化对比修改 3. 添加校验器验证栈映射帧 4. 使用JVM参数禁用字节码验证(仅调试) - -Xverify:none 七、发展趋势 1. 新一代工具涌现(如Byte Buddy) 2. 云原生场景的轻量化需求 3. 与GraalVM原生镜像的兼容适配 4. 安全增强要求(防止恶意代码注入) 理解字节码增强技术需要结合JVM规范深入研究,建议从简单的方法插桩开始实践,逐步掌握更复杂的类结构修改技术。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值