背景尽管在生产环境热更新代码,并不是很好的行为,很可能导致:热更不规范,同事两行泪。 但很多时候我们的确希望能热更新代码,比如: 线上排查问题,找到修复思路了,但应用重启之后,环境现场就变了,难以复现。怎么验证修复方案?
又比如: 本地开发时,发现某个开源组件有bug,希望修改验证。如果是自己编译开源组件再发布,流程非常的长,还不一定能编译成功。有没有办法快速测试?
Arthas是阿里巴巴开源的Java应用诊断利器,深受开发者喜爱。 下面介绍利用Arthas 3.1.0版本的 jad /mc /redefine 一条龙来热更新代码。 Arthas: https://github.com/alibaba/arthas jad命令: https://alibaba./arthas/jad.html mc命令: https://alibaba./arthas/mc.html redefine命令: https://alibaba./arthas/redefine.html
Arthas在线教程下面通过Arthas在线教程演示热更新代码的过程。 
arthas-online-hotswap 在例子里,访问 curl http://localhost/user/0 ,会返回500错误: { "timestamp": 1550223186170, "status": 500, "error": "Internal Server Error", "exception": "java.lang.IllegalArgumentException", "message": "id < 1", "path": "/user/0" }
下面通过热更新代码,修改这个逻辑。 jad反编译代码反编译UserController ,保存到 /tmp/UserController.java 文件里。 jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.java
修改反编绎出来的代码用文本编辑器修改/tmp/UserController.java ,把抛出异常改为正常返回: @GetMapping(value={"/user/{id}"}) public User findUserById(@PathVariable Integer id) { logger.info("id: {}", (Object)id); if (id != null && id < 1) { return new User(id, "name" id); // throw new IllegalArgumentException("id < 1"); } return new User(id.intValue(), "name" id); }
sc查找加载UserController的ClassLoader$ sc -d *UserController | grep classLoaderHash classLoaderHash 1be6f5c3
可以发现是spring boot的 LaunchedURLClassLoader@1be6f5c3 加载的。 mc内存编绎代码保存好/tmp/UserController.java 之后,使用mc(Memory Compiler)命令来编译,并且通过-c 参数指定ClassLoader : $ mc -c 1be6f5c3 /tmp/UserController.java -d /tmp Memory compiler output: /tmp/com/example/demo/arthas/user/UserController.class Affect(row-cnt:1) cost in 346 ms
redefine热更新代码再使用redefine命令重新加载新编译好的UserController.class : $ redefine /tmp/com/example/demo/arthas/user/UserController.class redefine success, size: 1
检验热更新结果再次访问 curl http://localhost/user/0 ,会正常返回: { "id": 0, "name": "name0" }
总结Arthas里 jad /mc /redefine 一条龙来线上热更新代码,非常强大,但也很危险,需要做好权限管理。 比如,线上应用启动账号是 admin,当用户可以切换到admin,那么 所以: 最后,Arthas提醒您: 诊断千万条,规范第一条,热更不规范,同事两行泪。
来源:http://www./content-4-119451.html
|