热部署与 DevTools

Spring Boot DevTools 通过双类加载器 + 自动重启机制,在代码修改后数秒内完成重新加载,显著缩短开发迭代周期。

引入依赖

// build.gradle
developmentOnly 'org.springframework.boot:spring-boot-devtools'
<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>   <!-- 不传递给依赖方,不打入生产 jar -->
</dependency>

DevTools 在以下情况自动禁用,无需手动移除:生产 jar 运行(java -jar)、完整打包的 war、单元测试运行期间(@SpringBootTest)。


核心功能

1. 自动重启(Auto Restart)

DevTools 使用双类加载器策略:

JVM
├── Base ClassLoader      加载不变的类(第三方 jar,不重启)
└── Restart ClassLoader   加载项目代码(修改后丢弃,重新加载)

监听 classpath 变化(target/classes/build/classes/),检测到 .class 文件变化后,只重建 Restart ClassLoader,速度比冷启动快 5~10 倍。

2. LiveReload

内置 LiveReload 服务器(端口 35729),文件变化后自动通知浏览器刷新页面。需在浏览器安装 LiveReload 扩展(Chrome / Firefox 均有)。

spring:
  devtools:
    livereload:
      enabled: true   # 默认 true
      port: 35729

3. 开发时属性覆盖

DevTools 自动应用一组开发友好的默认属性,例如:

属性DevTools 默认值生产默认值
spring.thymeleaf.cachefalsetrue
spring.freemarker.cachefalsetrue
logging.level.webDEBUGINFO
spring.h2.console.enabledtruefalse

这些覆盖只在 DevTools 存在时生效,不影响生产行为。


IDE 配置

IntelliJ IDEA

IDEA 默认不会自动编译,需要开启以下配置:

方式一:手动触发(稳定)

Build → Build Project(Ctrl+F9),每次改完代码手动编译一次,DevTools 检测到 .class 变化后自动重启。

方式二:自动编译(方便)

  1. Settings → Build, Execution, Deployment → Compiler → 勾选 Build project automatically
  2. Settings → Advanced Settings → 勾选 Allow auto-make to start even if developed application is currently running

开启后,焦点离开 IDEA 窗口时自动触发编译。

VS Code

安装 Spring Boot Extension Pack,它包含了 Spring Boot Dashboard 和自动重启支持。编辑 Java 文件保存后自动触发编译和重启。


触发重启的范围

默认监听整个 classpath,可精细控制:

spring:
  devtools:
    restart:
      enabled: true
      # 排除不需要触发重启的路径(静态资源变化不必重启)
      exclude: static/**,public/**,templates/**,META-INF/maven/**
      # 额外监听 classpath 之外的目录
      additional-paths: src/main/resources
      # 触发文件:只有该文件变化时才重启(配合 CI 使用)
      trigger-file: .reloadtrigger

触发文件(Trigger File)

适合批量修改多个文件后统一重启,而不是每改一个文件重启一次:

spring:
  devtools:
    restart:
      trigger-file: .reloadtrigger

修改完所有文件后,手动 touch .reloadtrigger(或在 IDEA 中保存该文件)触发一次重启。


全局 DevTools 配置

DevTools 支持在用户主目录下的全局配置文件,适用于所有项目:

# ~/.config/spring-boot/spring-boot-devtools.properties(macOS / Linux)
# C:\Users\<User>\.spring-boot-devtools.properties(Windows)
 
spring.devtools.restart.trigger-file=.reloadtrigger
spring.devtools.livereload.enabled=true

远程开发(Remote DevTools)

在远程服务器上运行的应用也可以享受 DevTools 热重启,适合云端开发环境:

# 服务端(远程 application.yml)
spring:
  devtools:
    remote:
      secret: my-dev-secret   # 鉴权密钥,防止生产环境被误用

服务端必须以 spring-boot-devtools 打包运行(生产模式下 DevTools 默认禁用,需显式启用):

java -Dspring.devtools.remote.secret=my-dev-secret -jar app.jar

本地 IDE 中运行 RemoteSpringApplication,指向远程地址:

Run Configuration → Main class: org.springframework.boot.devtools.RemoteSpringApplication
Program arguments: https://remote-host:8080

本地代码修改 → 本地编译 → DevTools 上传 .class 到远端 → 远端重启。


DevTools vs JRebel

对比项DevToolsJRebel
费用免费付费(商业授权)
热替换粒度重启 Restart ClassLoader真正的字节码热替换,无需重启
支持范围Spring Bean、配置任意 Java 类,含方法签名变化
速度秒级重启亚秒级替换
Spring 集成深度集成通用,需插件配合
适用场景日常开发,免费够用大型项目、频繁改动、追求极致效率

与测试的关系

@SpringBootTest 运行时 DevTools 自动禁用,不会影响测试行为。

若需要在测试中也使用 DevTools 的属性覆盖(如关闭模板缓存),可手动指定:

@SpringBootTest
@TestPropertySource(properties = "spring.thymeleaf.cache=false")
class IntegrationTest {}

测试配置详见 测试


常见问题

Q:改了代码但没有重启?

  • IDEA:检查是否开启自动编译,或手动 Ctrl+F9
  • 确认修改的文件在 classpath 监听范围内(不在 exclude 列表)
  • 检查 spring.devtools.restart.enabled=true

Q:重启太频繁,每改一行都重启? 配置 trigger-file,批量改完后统一触发。

Q:生产环境误打入了 DevTools? Maven/Gradle 的 optional/developmentOnly 配置可确保不传递依赖;java -jar 启动时 DevTools 会自动检测并禁用。

Q:DevTools 重启后 Spring Security Session 失效? 重启会销毁 JVM 内存中的 Session,可配合 Spring Session + Redis 持久化 Session,详见 Session管理


相关链接