SpringBoot - 热部署
# SpringBoot - 热部署
# 引入
平时使用SpringBoot开发应用时,修改代码后需要重新启动才能生效。如果你的应用足够大的话,启动可能需要好几分钟。有没有什么办法可以加速启动过程,让我们开发应用代码更高效呢?下面介绍两个热部署工具,一个是SpringBoot官方的热部署工具spring-boot-devtools
实现修改完代码后快速自动重启应用;另一个是JRebel 实现修改完代码后快速热加载变更的类,无需重启应用。
# 什么是热部署和热加载?
热部署和热加载是在应用正在运行的时候,自动更新(重新加载或者替换class等)应用的一种能力。(PS:spring-boot-devtools提供的方案也是要重启的,只是无需手动重启能实现自动加载而已。)
严格意义上,我们需要区分下热部署和热加载, 对于Java项目而言:
- 热部署
- 在服务器运行时重新部署项目
- 它是直接重新加载整个应用,这种方式会释放内存,比热加载更加干净彻底,但同时也更费时间。
- 热加载
- 在在运行时重新加载class,从而升级应用。
- 热加载的实现原理主要依赖java的类加载机制,在实现方式可以概括为在容器启动的时候起一条后台线程,定时的检测类文件的时间戳变化,如果类的时间戳变掉了,则将类重新载入。
- 对比反射机制,反射是在运行时获取类信息,通过动态的调用来改变程序行为; 热加载则是在运行时通过重新加载改变类信息,直接改变程序行为。
# 配置devtools实现热部署
# POM配置
添加spring-boot-devtools的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 可以防止将devtools依赖传递到其他模块中 -->
</dependency>
</dependencies>
2
3
4
5
6
7
# application.yml配置
spring:
devtools:
restart:
enabled: true # 设置开启热部署
additional-paths: src/main/java # 指定热部署的目录
exclude: test/** # 指定目录不更新
2
3
4
5
6
# IDEA配置
方式一:无任何配置时,手动触发重启更新(cmd+F9)
方式二: IDEA需开启运行时编译,自动重启更新(保存文件后触发)
IDEA设置中的 Build,Execution,Deployment->Compile,勾选:Build project automatically
IDEA设置中的Advanced Setttings里面的第一个设置:
# 简单测试
@RestController
public class DemoController {
@GetMapping("/demo")
public String demo() {
String message = "hello";
return message;
}
}
2
3
4
5
6
7
8
启动项目后,使用的加载器变为了 restartedMain 了,说明热部署已经成功。
浏览器访问接口地址输出字符串hello,修改字符串为hello world后保存文件或cmd+F9,刷新浏览器请求的接口可以看到输出变了(需要等一会,因为项目会自动重启一下)。
从实际场景考虑,其实不需要一直自动热部署,使用手动触发即可。
# devtools原理
spring-boot-devtools使用了两个类加载器ClassLoader,一个ClassLoader加载不会发生更改的类(第三方jar包),另一个ClassLoader(restart ClassLoader)加载会更改的类(自定义的类)。
后台启动一个文件监听线程(File Watcher),监测的目录中的文件发生变动时, 原来的restart ClassLoader被丢弃,将会重新加载新的restart ClassLoader。
因为文件变动后,第三方jar包不再重新加载,只加载自定义的类,加载的类比较少,所以重启比较快。这也是为什么,同样是重启应用,为什么不手动重启,建议使用spring-boot-devtools进行热部署重启。
# 如果不用devtools,还有什么选择?
在实际的开发过程中,一般去使用devtool工具, 因为:
- devtool本身基于重启方式,这种仍然不是真正的热替换方案,JRebel才是(它是收费的,可通过代理破解,后面文章介绍)
- 开发调试最重要的还是一种权衡
- 自动重启的开销如果和手动重启没有什么太大差别,那么还不如手动重启(按需重启)
- 多数情况下,如果是方法内部的修改或者静态资源的修改,在IDEA中是可以通过Rebuild(Ctrl + Shift + F9)进行热更的
# JRebel实现热部署
# 安装插件
# 激活插件
- 步骤一:生成一个GUID:在线生成GUID地址 (opens new window)
- 根据反向代理服务器地址拼接激活地址,服务器地址:
https://jrebel.qekang.com/{你生成的GUID}
# 使用插件
将我们的项目使用JRebel进行管理项目,勾选上。
使用JRebel插件启动项目:
修改java文件后,手动触发编译:Shift+Cmd+F9 即可。
源码可见:https://github.com/hengwen/spring-demo/tree/main/sprintboothotdeploy