场景:
windows环境,如果现场环境客户正在使用项目,如果要替换项目中的一个class文件,但是又不能重启服务改怎么处理,今天介绍使用arthas中的retransform命令动态替换及使用注意的事项。
环境:
windows,arthas,测试项目
替换前:
准备测试文件LoginController.class,准备对如下方法进行简单的修改替换
启动
启动时加上-Dfile.encoding=UTF-8 保证控制台不会出现中文乱码
java -Dfile.encoding=UTF-8 -jar arthas-boot.jar
反编译:
将线上LoginController.class文件使用jad反编译到指定的文件中
jad --source-only com.gisquest.platform.rest.sys.LoginController > D:/temp/LoginController.java
获取类加载器
获取线上加载LoginController.class的类加载hashcode.
sc -d com.gisquest.platform.rest.sys.LoginController
对反编译的文件修改
mc内存编译
使用mc命令将反编译的.java文件变成对应的.class文件
mc -c 27647ad0 D://temp/LoginController.java -d D://temp
Memory compiler error, exception message: Compilation Error
本地编译:
这里没有成功只能放到项目中编译了
redefine命令热加载
验证
观察到内存中加载的已经是修改后的方法,因此验证成功!!!!
相关问题及验证
问题一:mc命令将修改后的loginController.java文件编译成LoginController.class时为什么报错
问题二:redefine 和 retransform命令热加载区别
相同点:
-
正在跑的函数,没有退出不能生效,比如下面新增加的System.out.println,只有run()函数里的会生效
-
不允许新增加 field/method
-
加载外部的.class 文件,redefine jvm 已加载的类。
区别:
redefine命令和jad/watch/trace/monitor/tt等命令会冲突。执行完redefine之后,如果再执行上面提到的命令,则会把redefine的字节码重置
如果多次执行 retransform 加载同一个 class 文件,则会有多条 retransform entry.
推荐使用retransform命令
拓展
sc 命令搜索jvm加载的类信息
sc *LoginController
sc *LoginController -d | grep classLoaderHash
sm命令搜索jvm加载的方法信息
sm查询一个类中的所有方法
sm *LoginController -d | grep method-name
sm查询一个类中的所有方法中具体一个方法
sm *LoginController -d | grep method-name | grep sendVerificationCode
ognl命令
1.查看类中静态变量的信息
ognl @com.gisquest.platform.rest.sys.LoginController@deptUserProperties
原因是LoginController存在多个类加载器,需要指定classLoaderHash
如果静态变量是集合,可查看集合中key对应的value信息
ognl -c 6375bfd4 "@com.gisquest.platform.rest.sys.LoginController@deptUserProperties['id']"
注意:
@class@Field时,引号的使用