巧用类文件替换加速 DEBUG
相比你们肯定遇到不停改代码试错和定位问题。最朴素的方法,就是直接修改项目代码,重新构建和打包,并部署到测试环境。但是,如果你的项目是个中大型项目,启动流程漫长,触发代码分支繁琐,那就很让人烦躁。
脑补一下这样的流程:
- 项目构建,耗时5分钟
- 打包,耗时3分钟
- 上传到仓库系统,耗时3分钟
- 从测试环境拉取刚上传的 SNAPSHOT ,耗时10秒
- 修改版本,重新启动应用程序,耗时3分钟
- 手工操作,重现问题,耗时1分钟
这样加起来,10~15分钟就没了。虽然对于上班摸鱼的我们来说,问题不大。但是总有要赶项目进度的时候不是?
而对于上述场景,有相当多的时候只是为了加一行日志,调整一下标志位,或者修改一下方法参数。重新走一遍发布流程实在事倍功半。或许你需要的,只是简单替换一下类文件。
总所周知,.java
源代码经过编译后,生成 .class
字节码文件。JVM 读取 .class
文件,通过 ClassLoader 加载到内存中并执行。因此,要实现类替换,无非是替换 .class
文件,或者替换已经被加载到内存中的类。前者为静态替换,后者就是动态替换,或者说热替换。
静态替换
.tar.gz
以 .tar.gz
方式打包的 Java 程序,运行时需要先解压后执行。
.tar.gz
只是一个普通的压缩包文件。通过 tar -zxvf xxx.tar.gz
解压,会获得一堆 .class 文件。虽然不同的打包工具、不同的公司内部的实现,会有不同的打包方法。解压后获得的文件组织很可能会有所差异。但是最后,也不过是 java <Main.class> <arguments>
。java 命令行程序会加载所有类文件,并且启动指定类中的入口方法。
//TODO: demo
uber jar
Uber jar,又称 fat jar。其本质是一个以特定形式组织的 zip 压缩包。通过命令 unzip xxx.jar
解压后,也会获得一堆 .class 文件。替换完类文件后,通过命令 zip -r xxx.jar <files>
重新打包成 jar 包,就可以直接执行。
// TODO: demo
动态替换/热替换
JDB
Arthas
这里首推阿里巴巴开源的 Arthas 工具。Arthas 提供了 redefine 命令,读取外部的 .class 文件,加载并替换内存中的类。
// TODO: demo
IntelliJ IDEA
https://www.jetbrains.com/help/idea/altering-the-program-s-execution-flow.html#reload_classes
// TODO: can remote debug work?
Spring-Loaded
https://github.com/spring-projects/spring-loaded
DCEVM
Spring Hot Swapping
https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/howto-hotswapping.html