一、背景
很久之前就有一个想法:如果部署在线上的代码在遇到类似空指针异常时能自动修复就好了。前段时间准备尝试落实这个想法。那就先从基础做起:先在线改代码吧!
本来我是在学习字节码的,偶尔搜了一下资料,发现Arthas这个工具,能够实现代码热修改。
我仿佛发现了新大陆,于是添加收藏。这时我发现,我的收藏夹里很早就收藏了这个网页。看来有些路终究是要走的。
废话不说,试试吧!
二、准备
1、下载Arthas到电脑
直接从官网下就行。下那个最全的包,解压就好。
https://arthas.aliyun.com/doc/quick-start.html
2、写个小项目
我写了个springboot项目,里面主要就两个方法。
1)HelloController
@RestController public class HelloController { @GetMapping("/hello1") public String hello1(@RequestParam(value="name", defaultValue="world") String name) { return StringUtil.packHello(name); } }
2)StringUtil
public class StringUtil { public static String packHello(String name) { return String.format("Hello %s!", name); } }
三、开始
1、启动springboot项目
2、运行arthas,并选择目标进程
我这里选择2
java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.6.0
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 6784 org.jetbrains.jps.cmdline.Launcher
[2]: 6787 com.shuimutong.learn.arthos.helloweb.HelloWebApplication
3、使用sc命令查找要修改的类
我这里准备在StringUtil里加上一个打印,输入查找命令如下:
[arthas@6787]$ sc -d *util.StringUtil
class-info com.shuimutong.learn.arthos.helloweb.util.StringUtil
code-source /Users/zhengxingao/Documents/develop/arthoslearn/helloweb/target/classes/
name com.shuimutong.learn.arthos.helloweb.util.StringUtil
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name StringUtil
modifier public
annotation
interfaces
super-class +-java.lang.Object
class-loader +-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@32a1bec0
classLoaderHash 18b4aac2
4、使用jad命令反编译出源码
jad --source com.shuimutong.learn.arthos.helloweb.util.StringUtil > /tmp/StringUtil.java
输出目录建议选择/tmp,不用担心没有权限
5、编辑/tmp/StringUtil.java
arthas里面没法使用vi,所以新开窗口编辑吧。
/* * Decompiled with CFR. */ package com.shuimutong.learn.arthos.helloweb.util; public class StringUtil { public static String packHello(String name) { System.out.println("name:"+name); /* 5*/ return String.format("Hello %s!", name); } }
我加了个打印。
(那个/*5*/我也不知道咋回事,后面再了解吧)
6、编译文件
mc -c 18b4aac2 /tmp/StringUtil.java -d /tmp
Memory compiler output:
/tmp/com/shuimutong/learn/arthos/helloweb/util/StringUtil.class
Affect(row-cnt:1) cost in 194 ms.
-c后面跟的一串是字符是前面查找类时打印出的classLoadHash
7、加载编译的class
[arthas@6787]$ redefine /tmp/com/shuimutong/learn/arthos/helloweb/util/StringUtil.class
redefine success, size: 1, classes:
com.shuimutong.learn.arthos.helloweb.util.StringUtil
8、检验
请求:http://localhost:8081/hello1?name=arthas
控制台打印:name:arthas
符合预期。
四、小结
arthas是一个神器,代码热修改只是它的一个小功能。它还有许多监控方面的强大的功能。
至于它是怎么做到的,我还是继续学习字节码吧!
五、参考
1、https://arthas.aliyun.com/doc/quick-start.html
2、https://blog.csdn.net/qq_27184497/article/details/118875205
3、https://blog.csdn.net/weixin_46007214/article/details/117393545