Java OpenResty Spring Spring Boot MySQL Redis MongoDB PostgreSQL Linux Android Nginx 面试 小程序 Arthas JVM AQS juc Kubernetes Docker DevOps


Arthas 使用 retransform 热更新 Srping Boot 代码

Arthas Java Spring Boot 大约 7800 字

说明

本文基于Arthas 3.4.6

相关代码

package com.example.arthas.controller;

@Slf4j
@RestController
public class Test111Controller {

    @GetMapping("/test1")
    public Result test1(@RequestParam String key) {
        log.info("test1111111111111#{}", key);
        List<String> list = (List<String>) CollectionUtils.arrayToList(new String[]{"aaa", "bbb", "ccc"});
        return Result.builder().msg("请求成功").data(list).build();
    }

}

查看 Arthas 是否已经 attach

attach的监听3658端口。

ss -anpl | grep 3658

已监听,通过telnet进入。

telnet 127.0.0.1 3658

未监听,通过java -jar启动。

java -jar arthas-boot.jar

查看类信息

scsearch class-ddetail

找到classLoaderHash,类加载器的哈希值。

sc -d com.example.arthas.controller.Test111Controller

输出:

[arthas@89537]$ sc -d com.example.arthas.controller.Test111Controller
 class-info        com.example.arthas.controller.Test111Controller                                                                                                                             
 code-source       file:/home/root/demo/arthas-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/                                                                                                          
 name              com.example.arthas.controller.Test111Controller                                                                                                                             
 isInterface       false                                                                                                                                                                       
 isAnnotation      false                                                                                                                                                                       
 isEnum            false                                                                                                                                                                       
 isAnonymousClass  false                                                                                                                                                                       
 isArray           false                                                                                                                                                                       
 isLocalClass      false                                                                                                                                                                       
 isMemberClass     false                                                                                                                                                                       
 isPrimitive       false                                                                                                                                                                       
 isSynthetic       false                                                                                                                                                                       
 simple-name       Test111Controller                                                                                                                                                           
 modifier          public                                                                                                                                                                      
 annotation        org.springframework.web.bind.annotation.RestController                                                                                                                      
 interfaces                                                                                                                                                                                    
 super-class       +-java.lang.Object                                                                                                                                                          
 class-loader      +-org.springframework.boot.loader.LaunchedURLClassLoader@7daf6ecc                                                                                                           
                     +-sun.misc.Launcher$AppClassLoader@55f96302                                                                                                                               
                       +-sun.misc.Launcher$ExtClassLoader@1ed1993a                                                                                                                             
 classLoaderHash   7daf6ecc                                                                                                                                                                    

Affect(row-cnt:1) cost in 37 ms.

反编译已加载类的源码

--source-only:只输出源代码,重定向到/tmp目录下的Test111Controller.java文件中。

jad --source-only com.example.arthas.controller.Test111Controller > /tmp/Test111Controller.java

修改代码

vim /tmp/Test111Controller.java

编译反编译过的源码

mcMemory Compiler-c:指定类加载的哈希值,-d:存放.class文件的文件夹。

mc -c 7daf6ecc /tmp/Test111Controller.java -d /tmp

输出:最终.class路径位置/tmp/com/example/arthas/controller/Test111Controller.class

[arthas@89537]$ mc -c 7daf6ecc /tmp/Test111Controller.java -d /tmp
Memory compiler output:
/tmp/com/example/arthas/controller/Test111Controller.class
Affect(row-cnt:1) cost in 1174 ms.

如果不指定-c参数,可能出现以下错误。

[arthas@89537]$ mc /tmp/Test111Controller.java -d /tmp
Memory compiler error, exception message: Compilation Error
line: 12 , message: package org.slf4j does not exist , 
line: 13 , message: package org.slf4j does not exist , 
line: 14 , message: package org.springframework.web.bind.annotation does not exist , 
line: 15 , message: package org.springframework.web.bind.annotation does not exist , 
line: 17 , message: cannot find symbol
  symbol: class RestController , 
line: 19 , message: cannot find symbol
  symbol:   class Logger
  location: class com.example.arthas.controller.Test111Controller , 
line: 21 , message: cannot find symbol
  symbol:   class GetMapping
  location: class com.example.arthas.controller.Test111Controller , 
line: 19 , message: cannot find symbol
  symbol:   variable LoggerFactory
  location: class com.example.arthas.controller.Test111Controller , 
, please check $HOME/logs/arthas/arthas.log for more details.

热更新

加载外部的 .class 文件,替换原有JVM已加载的类。

retransform /tmp/com/example/arthas/controller/Test111Controller.class

输出:

[arthas@89537]$ retransform /tmp/com/example/arthas/controller/Test111Controller.class
retransform success, size: 1, classes:
com.example.arthas.controller.Test111Controller

retransform 列表

显示已经替换过的类

retransform -l

输出:

[arthas@89537]$ retransform -l
Id              ClassName       TransformCount  LoaderHash      LoaderClassName 
1               com.example.art 1               null            null            
                has.controller.                                                 
                Test111Controll                                                 
                er

恢复修改前代码

清除掉历史转换过的类,重新触发retransform以恢复修改之前的代码。

清除指定 retransform

清除id1entry

retransform -d 1

清除所有 retransform

retransform --deleteAll

重新触发 retransform 恢复修改之前的代码

使用--classPattern匹配需要恢复的代码。

retransform --classPattern com.example.arthas.controller.Test111Controller

输出

[arthas@89537]$ retransform --classPattern com.example.arthas.controller.Test111Controller
retransform success, size: 1, classes:
com.example.arthas.controller.Test111Controller

备注

  1. retransform过的类,在stopArthas后不会被reset,必须手动重新触发retransform
  2. 若没有清除retransform而停止了Arthas,则可以再次启动,重新jad-mc-retransformjad反编译得到的还是修改前的代码。
  3. retransform不允许新增加字段或方法。

Arthas 全量文件下载

https://github.com/alibaba/arthas/releases

参考

https://arthas.aliyun.com/doc/retransform.html

阅读 2323 · 发布于 2021-04-28

————        END        ————

Give me a Star, Thanks:)

https://github.com/fendoudebb

扫描下方二维码关注公众号和小程序↓↓↓

扫描二维码关注我
昵称:
随便看看 换一批