前言
在实际开发过程中,每次修改代码就得将项目重启,重新部署,对于一些大型应用来说,重启时间需要花费大量的时间成本。对于一个后端开发者来说,重启过程确实很难受。目前的java虚拟机只能实现方法体的热部署,对于整个类的结构修改,仍然需要重启虚拟机,对类重新加载才能完成更新操作。
热部署原理
说到热部署不得不提类的加载过程:加载、验证、准备、解析、初始化。
类的加载过程遵循双亲委派机制,就是在加载一个class的时候,会始终尝试先委派给父类加载器。我们只需要自定义类加载器,监听或通过其他途径监听文件的变动,使用自定义的类加载器重新进行加载即可。
idea内置热部署
step1:在IDEA中添加远程debug配置,host填服务器的ip,自定义一个端口号,会自动生成“Command line arguments remote JVM”参数。
setp2:启动java进程的时候添加VM参数,如果是docker环境还需要指定端口映射。
java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8008 app.jar
setp3:用debug方式启动本地服务,控制台出现“Connected to the target VM, address: ‘xxx:8008’, transport: ‘socket’”则表示连接成功。
setp4:修改本地代码,在修改类下面右击鼠标,点击“Compile And Reload File”按钮,会将本地编译好的class文件重新加载到远程JVM中。
arthas热部署
使用arthas热部署的原理是先使用jad将运行的class编译并输出为java文件,然后使用vim编辑java文件,再使用sc命令获取该类的类加载器,并用mc指定类加载器将java文件编译为class文件,最后使用redefine 将class重新加载进JVM中。
使用原生的arthas命令进行一次热部署是不是很麻烦?还好arthas团队为我们做了集成,直接在本地将java文件编译成字节码文件,并上传到阿里云SSO中,在服务器上直接执行脚本一键完成class文件替换。
setp1:在IDEA插件市场下载“ArthasHotSwap”插件,并重启IDEA使插件生效。
setp2:在需要修改的类界面右击"ArthasHotSwap->Swap This Class"
在剪切板中会出现如下文本:
sudo echo "curl -L http://xxxtai-arthas-hot-swap.oss-cn-beijing.aliyuncs.com/public/BLTc8kJKlU4fxfAHNXTrsjIHmCxyawmWrzPoxfOfPHw=x > HotSwapScript4OneClass.sh ;
echo 'fb5fbe0db736ab2c62fbd97e54858c39 HotSwapScript4OneClass.sh' > HotSwapScript4OneClass.md5sum;
md5sum --status -c ./HotSwapScript4OneClass.md5sum;
if [[ \$? -eq 0 ]]; then
chmod +x HotSwapScript4OneClass.sh;
yes | ./HotSwapScript4OneClass.sh 67723d1a566a622d7a1d624a79394831 561b4a10407a6212520564235652103e;
else
echo 'It is necessary to report this error to xxxtai@163.com!!!';
fi" > ArthasHotSwapMD5Check.sh; chmod +x ./ArthasHotSwapMD5Check.sh; ./ArthasHotSwapMD5Check.sh;
setp3:在服务器或者容器中执行剪切的文本
注意:由于ArthasHotSwap是使用阿里云SSO进行存储class文件进行中转,所以服务器必须要能够访问到阿里云SSO。
spring-boot-devtools热部署
spring-boot-devtools热部署分为三种模式:针对数据库配置热部署、本地热部署、远程热部署。
我们知道JVM判断两个类是否相同的第一个条件就是必须使用同一个类加载器进行加载的。spring-boot-devtools在启动main函数的时候会终止mian进程,会重新开启一个进程并替换类加载器进行加载mian,这样在每次监听到class变动的时候都会触发mian重启,所以它在热部署的过程中服务也是不可访问的,但它的优点是及时改变方法区外的内容也会生效。在重启的过程中,容器也会给每个类计算一个hash值,只有hash值发生变化了才会重新进行加载,以此来加快容器的启动过程。
setp1:添加maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<version>${spring-boot.version}</version>
</dependency>
setp2:在Configurations中添加一个Application,启动类选择“org.springframework.boot.devtools.RemoteSpringApplication”,端口号和Tomcat端口保持一致。
setp3:权限校验。 spring-boot-devtools与远程之间通讯需要一个秘钥,本地配置的秘钥和远程的秘钥一致即可。
spring.devtools.remote.secret=xxxx
另外本地服务与远程服务器之间交换信息也是通过http请求,所以如果系统有自己的权限校验,需要将下面接口这是为免校验 “ /.~~spring-boot!~”
setp4:启动本地服务,修改类文件,点击Build->Recompile xxx.java编译单个类,也可以编译整个Project
当本地应用监听到class文件变动会向远程服务发送热部署指令,上传class文件并进行重启服务。出现如下标识则标识热部署成功。
roject
[外链图片转存中…(img-PJuLCmCy-1665563024525)]
当本地应用监听到class文件变动会向远程服务发送热部署指令,上传class文件并进行重启服务。出现如下标识则标识热部署成功。