字节码编程,Javassist篇三《使用Javassist在运行时重新加载类「替换原方法输出不一样的结果」》

作者:小傅哥
博客:https://bugstack.cn
沉淀、分享、成长,让自己和他人都能有所收获!
一、前言
通过前面两篇 javassist 的基本内容,大体介绍了;类池(ClassPool)、类(CtClass)、属性(CtField)、方法(CtMethod),的使用方式,并通过创建不同类型的入参出参方法,基本可以掌握如何使用这样的代码结构进行字节码编程。
那么,今天我们尝试使用 javassist 去修改一个正在执行中的类里面的方法内容。也就是在运行时重新加载类信息
可能在你平时的 CRUD 开发中并没有想到过这样的 烧操作,但它却有很多的应用场景在使用,例如;
- 热部署常用在生产环境中,主要由于这样的系统不能频繁启停且启动耗时较长的应用。
- 另外一些组件化风控模型包,给外部使用。当模型包进行升级时并不需要外部重新部署,甚至不需要让你知道升级了。
- 再者会用于开发、调试中,可以非常有效的提升编码效率,解放码农的右手和左手。
人的大脑很难创造未知的事物,所以需要学习。请多看小傅哥的码文,少搞CRUD
关于字节编程中所有涉及的代码,都可以通过关注公众号:bugstack虫洞栈,回复:源码,进行获取。
二、开发环境
- JDK 1.8.0
- jdk1.8.0_161\lib\tools.jar - 需要使用到
jdi包 - javassist 3.12.1.GA
三、案例目标
为了让案例目标更具色彩,我们模拟一个谢飞机老婆,通过系统查询自己男朋友前女友数量的 危机 方法,需要紧急处理的过程。
为了保障家庭的和谐化解危机,我们通过动态重新加载类,将谢飞机前女友数量修改为0并返回。依次安定家庭和谐。最终谢飞机会给我钱,当做报酬
让谢飞机很慌的方法
public class ApiTest {
public String queryGirlfriendCount(String boyfriendName) {
return boyfriendName + "的前女友数量:" + (new Random().nextInt(10) + 1) + " 个";
}
}
可预见的结果;
你到底几个前女友!!!
谢飞机的前女友数量:3 个
谢飞机的前女友数量:5 个
谢飞机的前女友数量:8 个
四、技术实现
1. HotSwapper 操作类热加载
德莱联盟,王牌工程师,申请出栈
/**
* 公众号: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());
}
}
2. 知识点讲解
- 多线程模拟循环调用,这个方法会一直执行查询。在后续修改类之后输出的结果信息会有不同。
javassist.tools.HotSwapper,是javassist的包中提供的热加载替换类操作。在执行时需要启用 JPDA(Java平台调试器体系结构)。ctMethod.setBody,重写方法的内容在上面两个章节已经很清楚的描述了。$1 是获取方法中的第一个入参,大括号{}里是具体执行替换的方法体。- 最后使用
hs.reload执行热加载替换操作,这里的ctClass.toBytecode()获取的是处理后类的字节码。
五、测试结果
1. 引入tools.jar
2. 配置-agentlib
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
3. 执行测试
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毛钱给了王牌工程师小傅哥。

4. 效果演示
六、总结
- 没得办法,即使再好的技术不加点段子也没人看。只能坑我兄弟飞机了!德莱联盟,王牌工程师,申请出
栈 - 关于热加载修改类的操作,在实际场景中还是蛮多的,但一般都是比较苛刻的场景诉求。在平时开发中还是比较少遇到的,并且CRUD开发不会遇到。
Javassist对ASM这样的字节码操作封装起来提供的API确实很好操作,在一些场景下也不需要考虑JVM中局部变量和操作数栈。但如果需要更高的性能,可以考虑使用ASM。
字节码编程,Javassist篇三《使用Javassist在运行时重新加载类「替换原方法输出不一样的结果」》的更多相关文章
- PHP 进阶篇:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 (麦子学员 第三阶段)
以下是进阶篇的内容:面向对象的设计原则,自动加载类,类型提示,traits,命名空间,spl的使用,反射的使用,php常用设计模式 ================================== ...
- 字节码编程,Javassist篇一《基于javassist的第一个案例helloworld》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 目录 @ 目录 目录 一.前言 二.开发环境 三.案例目标 四.技术实现 五.测试结果 1. ...
- 字节码编程,Javassist篇二《定义属性以及创建方法时多种入参和出参类型的使用》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 在上一篇 Helloworld 中,我们初步尝试使用了 Javassist字节编程的 ...
- 字节码编程,Byte-buddy篇一《基于Byte Buddy语法创建的第一个HelloWorld》
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 相对于小傅哥之前编写的字节码编程: ASM.Javassist 系列,Byte Bu ...
- Javassist之使用字节码在运行时生成新的类 01
介绍 Javassist是一个开源的分析.编辑和创建Java字节码的类库.是由东京工业大学的数学和计算机科学系的 Shigeru Chiba (千叶 滋)所创建的.它已加入了开放源代码JBoss 应用 ...
- [源码解析] 深度学习流水线并行 PipeDream(4)--- 运行时引擎
[源码解析] 深度学习流水线并行 PipeDream(4)--- 运行时引擎 目录 [源码解析] 深度学习流水线并行 PipeDream(4)--- 运行时引擎 0x00 摘要 0x01 前言 1.1 ...
- VSTO学习笔记(三) 开发Office 2010 64位COM加载项
原文:VSTO学习笔记(三) 开发Office 2010 64位COM加载项 一.加载项简介 Office提供了多种用于扩展Office应用程序功能的模式,常见的有: 1.Office 自动化程序(A ...
- 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理
服务器文档下载zip格式 刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...
- [WP8.1UI控件编程]Windows Phone大数据量网络图片列表的异步加载和内存优化
11.2.4 大数据量网络图片列表的异步加载和内存优化 虚拟化技术可以让Windows Phone上的大数据量列表不必担心会一次性加载所有的数据,保证了UI的流程性.对于虚拟化的技术,我们不仅仅只是依 ...
随机推荐
- 全网最全最细的jmeter接口测试教程以及接口测试流程详解
一.Jmeter简介 Jmeter是由Apache公司开发的一个纯Java的开源项目,即可以用于做接口测试也可以用于做性能测试. Jmeter具备高移植性,可以实现跨平台运行. Jmeter可以实 ...
- window 下 jmeter+ant 自动生成html报告并发送邮件
一.安装ant 1.ant 下载地址:https://ant.apache.org/bindownload.cgi 2.下载完成解压到指定目录下 3.配置ant 环境变量 新建系统变量 -ANT_HO ...
- HTML+CSS教程(二)frameset框架和iframe内嵌
一.框架 (frameset)1.用<frameset></frameset>代替了<body></body>2.rows设置行的占页面的百分比:col ...
- SpringMVC视图解析中的 forward: 与 redirect: 前缀
在 SpringMVC 中,可以指定画面的跳转方式.使用 forward: 前缀实现请求转发跳转,使用 redirect: 前缀实现重定向跳转.有前缀的转发和重定向操作和配置的视图解析器没有关系,视图 ...
- pytorch 文本情感分类和命名实体识别NER中LSTM输出的区别
文本情感分类: 文本情感分类采用LSTM的最后一层输出 比如双层的LSTM,使用正向的最后一层和反向的最后一层进行拼接 def forward(self,input): ''' :param inpu ...
- 二叉树中两节点的最近公共父节点(360的c++一面问题)
面试官的问题:写一个函数 TreeNode* Find(TreeNode* root, TreeNode* p, TreeNode* q) ,返回二叉树中p和q的最近公共父节点. 本人反应:当时有点 ...
- tp5.0--多个条件查询全部数据
用where来查询的话(非主键): 查找:
- MAC地址欺骗(原理及实验)
MAC地址欺骗 MAC地址欺骗(或MAC地址盗用)通常用于突破基于MAC地址的局域网访问控制,例如在交换机上限定只转发源MAC地址修改为某个存在于访问列表中的MAC地址即可突破该访问限制,而且这种修改 ...
- ansible的剧本play(四)
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA68AAAETCAYAAADZDzDOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjw
- 都2020年了,这5个java IDE神器你还不知道?
TIOBE的4月份编程语言排行榜出来了,java还是稳坐第一位,java最新的版本也到了13,一直以来java凭借其企业级应用的优势和大量的框架级应用俘获了大量的粉丝和企业客户. 谈到开发者,java ...