做者:小傅哥
博客:https://bugstack.cnjava
沉淀、分享、成长,让本身和他人都能有所收获!
经过前面两篇 javassist
的基本内容,大致介绍了;类池(ClassPool)、类(CtClass)、属性(CtField)、方法(CtMethod),的使用方式,并经过建立不一样类型的入参出参方法,基本能够掌握如何使用这样的代码结构进行字节码编程。编程
那么,今天咱们尝试使用 javassist
去修改一个正在执行中的类里面的方法内容。也就是在运行时从新加载类信息api
可能在你平时的 CRUD 开发中并无想到过这样的 烧操做,但它却有不少的应用场景在使用,例如;多线程
人的大脑很难创造未知的事物,因此须要学习。请多看小傅哥的码文,少搞CRUDapp
关于字节编程中全部涉及的代码,均可以经过关注公众号
:bugstack虫洞栈,回复:源码,进行获取。dom
jdi
包为了让案例目标更具色彩
,咱们模拟一个谢飞机老婆,经过系统查询本身男友前女朋友数量
的 危机 方法,须要紧急处理的过程。socket
为了保障家庭的和谐化解危机,咱们经过动态从新加载类,将谢飞机前女朋友数量修改成0
并返回。依次安定家庭和谐。最终谢飞机会给我钱,当作报酬组件化
让谢飞机很慌的方法性能
public class ApiTest { public String queryGirlfriendCount(String boyfriendName) { return boyfriendName + "的前女朋友数量:" + (new Random().nextInt(10) + 1) + " 个"; } }
可预见的结果;学习
你到底几个前女朋友!!! 谢飞机的前女朋友数量:3 个 谢飞机的前女朋友数量:5 个 谢飞机的前女朋友数量:8 个
德莱联盟,王牌工程师,申请出栈
/** * 公众号:bugstack虫洞栈 * 博客栈:https://bugstack.cn - 沉淀、分享、成长,让本身和他人都能有所收获! * 本专栏是小傅哥多年从事一线互联网Java开发的学习历程技术汇总,旨在为你们提供一个清晰详细的学习教程,侧重点更倾向编写Java核心内容。若是能为您提供帮助,请给予支持(关注、点赞、分享)! */ public class GenerateClazzMethod { public static void main(String[] args) throws Exception { ApiTest apiTest = new ApiTest(); System.out.println("你到底几个前女朋友!!!"); // 模拟谢飞机老婆一顿查询 new Thread(() -> { while (true){ System.out.println(apiTest.queryGirlfriendCount("谢飞机")); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); // 监听 8000 端口,在启动参数里设置 // java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 HotSwapper hs = new HotSwapper(8000); ClassPool pool = ClassPool.getDefault(); CtClass ctClass = pool.get(ApiTest.class.getName()); // 获取方法 CtMethod ctMethod = ctClass.getDeclaredMethod("queryGirlfriendCount"); // 重写方法 ctMethod.setBody("{ return $1 + \"的前女朋友数量:\" + (0L) + \" 个\"; }"); // 加载新的类 System.out.println(":: 执行HotSwapper热插拔,修改谢飞机前女朋友数量为0个!"); hs.reload(ApiTest.class.getName(), ctClass.toBytecode()); } }
javassist.tools.HotSwapper
,是 javassist
的包中提供的热加载替换类操做。在执行时须要启用 JPDA(Java平台调试器体系结构)。ctMethod.setBody
,重写方法的内容在上面两个章节已经很清楚的描述了。$1 是获取方法中的第一个入参,大括号{}
里是具体执行替换的方法体。hs.reload
执行热加载替换操做,这里的 ctClass.toBytecode()
获取的是处理后类的字节码。-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
Listening for transport dt_socket at address: 8000 你到底几个前女朋友!!! 谢飞机的前女朋友数量:3 个 谢飞机的前女朋友数量:5 个 谢飞机的前女朋友数量:8 个 :: 执行HotSwapper热插拔,修改谢飞机前女朋友数量为0个! 谢飞机的前女朋友数量:4 个 谢飞机的前女朋友数量:5 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 谢飞机的前女朋友数量:0 个 ... Process finished with exit code -1
当看到前女朋友数量为 0 时,谢飞机露出了羞涩的微笑,并兑现了承诺,将4毛钱给了王牌工程师小傅哥
。
栈
Javassist
对 ASM
这样的字节码操做封装起来提供的API
确实很好操做,在一些场景下也不须要考虑 JVM
中局部变量和操做数栈。但若是须要更高的性能,能够考虑使用 ASM
。