阿里Arthas(阿尔赛斯)不停机替换class进行热部署

1.启动待测试的应用程序

[doda@host166 game]$ java -jar math-game.jar 

2.替换操作步骤 

2.1启动Arthas

[doda@host166 arthas]$ java -jar arthas-boot.jar
[INFO] arthas-boot version: 3.6.1
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 316194 org.elasticsearch.bootstrap.Elasticsearch
  [2]: 105913 smart-spark-1.0.jar
  [3]: 164109 math-game.jar
3
[INFO] arthas home: /home/doda/shangeshishi/arthas
[INFO] Try to attach process 164109
[INFO] Attach process 164109 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          

wiki       https://arthas.aliyun.com/doc                                        
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html                  
version    3.6.1                                                                
main_class                                                                      
pid        164109                                                               
time       2022-05-15 15:33:34  

2.2使用redefine命令替换的类进行反编译替换操作(不可还原)

 #jad反编译出java文件,只显示源码,最后是文件反编译之后的存放路径
[arthas@151998]$ jad --source-only demo.MathGame > /home/doda/shangeshishi/arthas/game/MathGame.java
#修改反编译出来的java文件
[doda@host166 game]$ vi MathGame.java
#sc全称-search class,-d表示detail,获取类加载器classLoaderClass的hashCode编码
[arthas@164109]$ sc -d *MathGame | grep classLoader
 classLoaderHash   42a57993
#用指定的classloader重新将类在内存中编译,生成.class文件到本地
[arthas@164109]$ mc -c 42a57993 /home/doda/shangeshishi/arthas/game/MathGame.java -d /home/doda/shangeshishi/arthas/game
Memory compiler output:
/home/doda/shangeshishi/arthas/game/demo/MathGame.class
Affect(row-cnt:1) cost in 970 ms.
#用redefine命令将本地编译后的.class类加载到JVM
 [arthas@164109]$ redefine  /home/doda/shangeshishi/arthas/game/demo/MathGame.class
redefine success, size: 1, classes:
demo.MathGame

替换class前后日志对比,代码添加的:System.out.println("出异常信息了!!!");已经马止打印出来,可见替换class已经成功了!

注意:如果mc编译中报下面错误,即有可能是使用openJdk,此jdk中缺少tool工具包,请临时引入完整jdk,用当前引入的jdk,然后重启应用和Arthas,即可解决:
Memory compiler error, exception message: Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(), please confirm the application running in JDK not JRE., please check $HOME/logs/arthas/arthas.log for more details.
[doda@host166 arthas]$ export JAVA_HOME=/home/doda/shangeshishi/jdk/jdk1.8.0_131
[doda@host166 arthas]$ export PATH=$JAVA_HOME/bin:$PATH
[doda@host166 arthas]$ export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
[doda@host166 arthas]$ java -version
java version "1.8.0_131"
Java(TM) SE Runtime Environment (build 1.8.0_131-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

2.3使用retransform实现redefine替换(可还原)

2.3.1替换操作

[doda@host166 arthas]$ java -jar arthas-boot.jar
[arthas@164109]$  sc -d *MathGame | grep classLoader
 classLoaderHash   42a57993
[arthas@164109]$ mc -c 42a57993 /home/doda/shangeshishi/arthas/game/MathGame.java -d /home/doda/shangeshishi/arthas/game
Memory compiler output:
/home/doda/shangeshishi/arthas/game/demo/MathGame.class
Affect(row-cnt:1) cost in 310 ms.
[arthas@164109]$ retransform /home/doda/shangeshishi/arthas/game/demo/MathGame.class
retransform success, size: 1, classes:
demo.MathGame

修改替换后的日志如下

2.3.2retransform常用操作命令

查看 retransform entry,替换多少次显示多少次
[arthas@164109]$ retransform -l
Id              ClassName       TransformCount  LoaderHash      LoaderClassName 
1               demo.MathGame   1               null            null            
2               demo.MathGame   1               null            null            

删除指定id的 retransform entry
[arthas@164109]$ retransform -d 1
[arthas@164109]$ retransform -l
Id              ClassName       TransformCount  LoaderHash      LoaderClassName 
2               demo.MathGame   1               null            null 

删除所有 retransform entry
[arthas@164109]$ retransform --deleteAll

2.3.3消除 retransform 的影响,即还原替换前的class(使用redefine不可还原)

删除这个类对应的 retransform entry
重新触发retransform
对于同一个类,当存在多个 retransform entry时,如果显式触发 retransform ,则最后添加的entry生效(id最大的)

[arthas@164109]$ retransform --deleteAll
[arthas@164109]$ retransform --classPattern demo.MathGame

删除后,显式触发 retransform,可以还原原来的class,显示日志如下:

3.redefine和retransform替换class限制

        都不允许新增加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());
        }
    }

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值