先简单介绍下文章中使用是springboot项目,采用的工具是arthas
关于arthas的命令、以及官网地址这里贴以下出来arthas官方文档
这里先说明下,arthas有在线反编译class文件(jad命令)->修改源文件->重新编译(mc命令) 这样的流程来修改文件。这里在网上找到一篇对应这个流程的示例
但是基本上重新编译这个操作很少成功(因为试了几次变更都是因为依赖其他类导致)。所以我这边直接选择使用retransform命令完成的
class文件如何替换
步骤一:将我们修改后源文件编译后的最新的class文件上传服务器
这里项目使用的docker部署
这里使用几个命令来完成,将我们编译好的最新class文件上传到指定目录比如/tmp
当然这里的/tmp为docker里面的目录
docker ps -a | grep 项目名称
找到容器前面的id后,我们使用docker cp命令将服务器本地文件拷贝到容器/tmp目录下
docker cp xxx.class 容器id:/tmp
执行命令如果没有错误提示的话,基本上就成功执行了,当然需要验证的话,我们可以直接进入docker容器里面查看对应/tmp目录是否有该文件。
docker exec -it 容器id bash
这里就不再演示了
步骤二:进入容器下载arthas,执行命令
进入容器命令
docker exec -it 容器id bash
进来后,执行下面命令下载arthas包,敲下回车键就可以下载对应jar包
curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar
按命令1会attach到我们的应用进程
显示这样子之后,也就代表我们的命令操作完成,也是很正常。执行下面关键命令,如果出来success的字样,代表我们在内存中已经替换完成。
retransform /tmp/xxxx.class
当然执行完成后,我们在控制台输入exit命令,退出arthas控制台会话。如果我们不需要使用arthas操作其他,可以使用stop命令关闭,不占用线上服务器任何资源、
注意
在我们上面执行完后,在docker容器中我们在arthas客户端命令执行quit或者exit命令,执行关闭下会话,因为有可能因为其他人操作命令session没有关闭,导致执行找不到对应的class文件(执行命令对应目录下的文件实际是存在的)。我们可以尝试完全退出 arthas,执行stop
命令。
retransform命令限制
如果提示这个异常错误:retransform error! java.lang.UnsupportedOperationException: class redefinition failed: attempted to change the schema (add/remove fields)
是否出现了以下几种情况
- 不允许新增加 field/method
- 正在跑的函数,没有退出不能生效,比如下面新增加的
System.out.println
,只有run()
函数里的会生效
public class MathGame {
public static void main(String[] args) throws InterruptedException {
MathGame game = new MathGame();
while (true) {
game.run();
TimeUnit.SECONDS.sleep(1);
// 这个不生效,因为代码一直跑在 while里
System.out.println("in loop");
}
}
public void run() throws InterruptedException {
// 这个生效,因为run()函数每次都可以完整结束
System.out.println("call run()");
try {
int number = random.nextInt();
List<Integer> primeFactors = primeFactors(number);
print(number, primeFactors);
} catch (Exception e) {
System.out.println(String.format("illegalArgumentCount:%3d, ", illegalArgumentCount) + e.getMessage());
}
}
}
这个限制请参考官网的同步更新retransform | arthas