如何不重启热更新线上 Java 代码?
一、前言
热更新代码的场景
1)当线上服务器出现问题时,有些时候现有的手段不足以发现问题所在,可能需要追加打印日志或者增加一些调试代码,如果我们去改代码重新部署,会破坏问题现场,可以通过热部署的手段来增加调试代码
2)线上出现紧急bug,通过Review代码找到问题,修改好后打包部署的流程可能比较久,可以通过热部署代码及时解决问题。
二、Arthas的使用
使用阿里巴巴开源的Java诊断工具---Arthas,他可以附着在我们的Java服务器进程上面,查看服务器状态,jvm状态等各种参数指标,还可以进行热更新。
1、下载启动Arthas
wget https://alibaba.github.io/arthas/arthas-boot.jarjava -jar arthas-boot.jar
2、启动后会显示当前机器上面所有的java进程,选择我们需要监控/修改的进程,输入序号回车
3、一些常用命令,如果线上出现问题,可以通过以下命令查看各项指标是否有异常
dashboard——当前系统的实时数据面板
thread——查看当前 JVM 的线程堆栈信息
jvm——查看当前 JVM 的信息
sysprop——查看和修改JVM的系统属性
sysenv——查看JVM的环境变量
getstatic——查看类的静态属性
1)打印前五名最消耗CPU的线程,可以及时找到CPU过高的代码位置
thread -n 5
2)查看某个函数的调用堆栈
stack <类全包名> <函数名>
3)查看某个函数的哪个子调用最慢,耗时最久的调用会标红显示,可以方便找出某个功能中最耗时的操作
trace <类全包名> <函数名>
4)监控某个函数的调用统计数据,包括总调用次数,平均运行时间,成功率等信息
monitor <类全包名> <函数名>
4、输入exit可以退出当前的连接,但是附着在服务器进程上的Arthas依然在运行,完全退出可以输入shutdown
三、热更新
1、首先找到我们需要更新代码的全包名,通过jad命令将线上正在运行的代码反编译出来
jad --source-only <全包名> > <导出目录+文件名>
2、拿到java代码后,我们根据需求来修改代码,需要注意的是这里热更新代码的实际原理是调用Java基础类java.lang.instrument.Instrumentation的redefineClasses方法,他可以通过修改字节码来替换已有的class文件,其中有诸多的限制:
1)比如不能增加或删除field/method
2)没有退出的函数不能生效,比如一个函数体内是一个where(true)循环,永远不会结束,那么我们修改的代码也永远不会生效
我们可以在函数中增加一些代码,比如增加日志打印等
3、修改好代码后,我们要找到这个这个类对应的类加载器,再去加载这个class,执行如下命令会返回类加载器的对象地址
sc -d <全包名> | grep classLoaderHash
4、通过内存编译将Java文件编译成Class文件
mc -c <类加载器的对象地址> <Java文件所在目录+文件名>
5、最后,我们通过命令将class文件进行热更新
redefine <Class文件所在目录+文件名>
6、更新完毕不出意外会立即生效,这时候就可以去验证代码是否生效了
推荐去我的博客阅读更多:
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
觉得不错,别忘了点赞+转发哦!
相关文章
- druid:java代码创建连接池
- Java、PHP、Python、JS 等开发者都如何绘制统计图
- Java基础-JVM
- java代码实现如何获取当前经纬度?(安卓的话可以用GPS取)
- java基础知识15 final关键字
- Java 10 的 10 个新特性,将彻底改变你写代码的方式!
- Java Socket应用(二)——java中InetAddress的应用
- JAVA学习笔记之SVN代码回滚
- java代码规范参考文档
- 【Java并发编程】之十六:深入Java内存模型——happen-before规则及其对DCL的分析(含代码)
- JAVA 设计模式 访问者模式
- Java内存模型
- 20个开发人员非常有用的Java功能代码
- 【基于MVC+Swing+Java的愤怒的小鸟游戏的设计与实现(效果+代码+论文 获取~~)】
- 文件传输基础----Java IO流
- java代码绘制生成图片(用于多张图片合成)
- 深度剖析Java变量栈&对象堆
- 完整java开发中JDBC连接数据库代码和步骤
- java连接各种数据库代码大全
- Java InputStream流转换读取成String字符串方法及示例代码
- Java 对微信小程序包wxapkg解包(反编译)解码方法及示例代码
- Java EasyExcel读取多行头(Header)数据方法及示例代码
- Java 不同于java.util.Random生成随机数的方法及示例代码
- Zookeeper的Shell 客户端操作和zookeeper java api 代码
- Java在一定范围随机生成经纬度
- Java中非静态成员变量、静态成员变量的初始化时机
- Linux Eclipse代码提示功能设置(Java & C/C++)